Click here to Skip to main content
15,881,413 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I wrote an ISAPI extension in C++ whose purpose is to run PowerBuilder code in IIS. PowerBuilder has an interface to allow C++ code to call directly into PowerBuilder code.

One of the features allows it to kick off a background thread using CreateThread and return to the client before the background thread is finished.

One of the users is having a problem where if two client apps request the same thing at about the same time, one of them aborts at a certain point in the PowerBuilder code executed by the background thread.

In IIS the AppPool is a process and each request is a thread. If two request threads can successfully run PowerBuilder code at the same time, why can't threads created by the request threads run successfully?

What I have tried:

This is the code that kicks off the background thread:

C++
if (RunBackground) {
       // create the background thread
       hThread = CreateThread(NULL, 0, BackgroundThread, strArgument, 0, &dwThreadID);
       if (hThread != NULL) {
           // wait for background thread to finish setup
           if (strArgument->hEvent != NULL) {
               WaitForSingleObject(strArgument->hEvent, INFINITE);
           }
           // cleanup
           delete strArgument;
           CloseHandle(hThread);
           CloseHandle(strArgument->hEvent);

           // set the HTTP status
           pECB->dwHttpStatusCode = HTTP_STATUS_OK;

           return HSE_STATUS_PENDING;
       }
   }


The BackgroundThread function initializes the PowerBuilder runtime and before calling the user code, does the following:

C++
// signal that initialization is done
if (strArgument->hEvent != NULL) {
    SetEvent(strArgument->hEvent);
}

// release the session
pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL);
Posted
Updated 17-Jun-20 22:05pm
v3

1 solution

delete strArgument;
CloseHandle(hThread);
CloseHandle(strArgument->hEvent);
One immediate problem is that you are using memory after freeing it. (Also note that not all paths free this memory. Does strArgument need to be allocated? If so consider using std::unique_ptr or just instantiate the strArgument class on the stack and have it clean up internally if need be.)

I'm puzzled by the second block of code. Is there more code before releasing the session? Will it matter if the first block finishes between calls to SetEvent and ServerSupportFunction?
 
Share this answer
 
Comments
Roland M Smith 18-Jun-20 8:17am    
The structure strArgument is deleted after the 'if' statement in the first snippet. The second snippet is in the middle of the BackgroundThread function. All uses of the structure in the background thread are before the second snippet so I am not using released memory.
Joe Woodbury 18-Jun-20 13:26pm    
delete strArgument; <==== delete
CloseHandle(hThread);
CloseHandle(strArgument->hEvent); <==== use
Joe Woodbury 18-Jun-20 13:30pm    
Further if hEvent is NULL, you may use strArgument in thread after deleting it in the calling function. (I've only seen CreateEvent fail in stress code designed to use up all handles and the thread creation would likely have failed in that case, but strictly speaking....)
Roland M Smith 18-Jun-20 15:34pm    
Thanks for pointing out that I was deleting the structure before referencing it.

Why should I delete the 'delete'?
Joe Woodbury 18-Jun-20 15:49pm    
With C++, take advantage of RAII which helps prevent leaks due to losing track of exit points.

My own preference is to create a class encapsulating the thread and transferring ownership of the data to that class/thread. I'd duplicate the event handle (in a class) in the calling function so I don't need to worry about the lifetime.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900