How to properly implement and close sleeping thread in a Windows DLL - multithreading

I have a native Windows DLL written in C. This DLL is designed to be loaded (injected) in different Windos processes. This DLL creates some working threads that look like this:
while(1) {
// do work
Sleep(few secs);
}
The problem is if the process exits and DLL unloads while thread is in Sleep() it will crash the process when it comes back from Sleep (thread will try to execute code that is not there). I was thinking of using TerminateThread() with the DllUnload handler but MSDN says it should be used in most extreme cases only. For example - my threads use critical sections and the documentation says:
If the target thread owns a critical section, the critical section will not be released.
How do I cleanly close the thread that is sleeping when the DLL is unloading? Should I redesign my working threads to do work in some other way?

Create an event:
HANDLE threadTerminationEvent = CreateEvent(.....);
Use WaitForSingleObject instead of Sleep:
while (1)
{
...........
if (WaitForSingleObject(threadTerminationEvent, few secs) != WAIT_TIMEOUT)
break;
}
// release resources and end thread
Wait for the thread to end itself:
SetEvent(threadTerminationEvent); // “please, die”
WaitForSingleObject(hThread, INFINITE);

Related

How to close thread winapi

what is the rigth way to close Thread in Winapi, threads don't use common resources.
I am creating threads with CreateThread , but I don't know how to close it correctly in ,because someone suggest to use TerminateThread , others ExitThread , but what is the correct way to close it .
Also where should I call closing function in WM_CLOSE or WM_DESTROY ?
Thx in advance .
The "nicest" way to close a thread in Windows is by "telling" the thread to shutdown via some thread-safe signaling mechanism, then simply letting it reach its demise its own, potentially waiting for it to do so via one of the WaitForXXXX functions if completion detection is needed (which is frequently the case). Something like:
Main thread:
// some global event all threads can reach
ghStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// create the child thread
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
//
// ... continue other work.
//
// tell thread to stop
SetEvent(ghStopEvent);
// now wait for thread to signal termination
WaitForSingleObject(hThread, INFINITE);
// important. close handles when no longer needed
CloseHandle(hThread);
CloseHandle(ghStopEvent);
Child thread:
DWORD WINAPI ThreadProc(LPVOID pv)
{
// do threaded work
while (WaitForSingleObject(ghStopEvent, 1) == WAIT_TIMEOUT)
{
// do thread busy work
}
return 0;
}
Obviously things can get a lot more complicated once you start putting it in practice. If by "common" resources you mean something like the ghStopEvent in the prior example, it becomes considerably more difficult. Terminating a child thread via TerminateThread is strongly discouraged because there is no logical cleanup performed at all. The warnings specified in the `TerminateThread documentation are self-explanatory, and should be heeded. With great power comes....
Finally, even the called thread invoking ExitThread is not required explicitly by you, and though you can do so, I strongly advise against it in C++ programs. It is called for you once the thread procedure logically returns from the ThreadProc. I prefer the model above simply because it is dead-easy to implement and supports full RAII of C++ object cleanup, which neither ExitThread nor TerminateThread provide. For example, the ExitThread documentation :
...in C++ code, the thread is exited before any destructors can be called
or any other automatic cleanup can be performed. Therefore, in C++
code, you should return from your thread function.
Anyway, start simple. Get a handle on things with super-simple examples, then work your way up from there. There are a ton of multi-threaded examples on the web, Learn from the good ones and challenge yourself to identify the bad ones.
Best of luck.
So you need to figure out what sort of behaviour you need to have.
Following is a simple description of the methods taken from documentation:
"TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
If the target thread owns a critical section, the critical section will not be released.
If the target thread is allocating memory from the heap, the heap lock will not be released.
If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL."
So if you need your thread to terminate at any cost, call this method.
About ExitThread, this is more graceful. By calling ExitThread, you're telling to windows you're done with that calling thread, so the rest of the code isn't going to get called. It's a bit like calling exit(0).
"ExitThread is the preferred method of exiting a thread. When this function is called (either explicitly or by returning from a thread procedure), the current thread's stack is deallocated, all pending I/O initiated by the thread is canceled, and the thread terminates. If the thread is the last thread in the process when this function is called, the thread's process is also terminated."

ISAPI Extension TerminateExtension thread deadlock

I needed to create statefull ISAPI extension for my project. I successfully made a TSession object that is contained in a TSessionList = class(TObject). For cleanup of expired sessions I made a cleanup thread (TThread descendant) that periodically scans TSessionList and frees all expired sessions.
I create the TSessionList and the CleanupThread in the dpr main execution block. Which is just fine. But actually I am not sure, where to put the destruction of CleanupThread. From documentation I found that ISAPI extension has to export TerminateExtension, which gets called just before the extension is unloaded. Default Delphi ISAPI extension of course exports such a function. So I've "overriden it" = exported my TerminateExtension that frees my session objects and then call default ISAPIAPP.TerminateExtensionProc.
Here it is how it looks like:
function TerminateExtension(dwFlags: DWORD): BOOL; stdcall;
begin
DoneSessions;
Result:= ISAPIApp.TerminateExtension(dwFlags);
end;
exports
GetExtensionVersion,
HttpExtensionProc,
TerminateExtension;
begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
InitSessions;
Application.CreateForm(TSOAPWebModule, SOAPWebModule);
Application.Run;
end.
The CleanupThread destruction is done in DoneSessions this way:
begin
CleanupThread.Free;
SessionList.Free;
end;
The CleanupThread is simple descendant of TThread, so do not look for anything specific in its destruction code.
The problem is that the TerminateExtension freezes just in CleanupThread.Free. Debugging further I did find that freeze happens in the TThread.WaitFor. I suspect there must be some kind of thread deadlock = ISAPI worker thread is waiting for my extension to terminate, which waits in TThread.WaitFor for the main thread to get signaled (or whatever).
I know I could overcome this situation calling CleanupThread.Terminate, then using direct WaitForSingleObject (or Multiple???) and finally freeing it. But that sounds a bit ... nonstandard.
Therefore my question is: How and when should i Free (Terminate - WaitFor - Destroy) any support threads in ISAPI extension to avoid thread deadlock?
BTW: I already found the same in standard DLL. If you put any thread.WaitFor in the dll unload proc, your main app freezes just in library unload. So the same question/answer hopefully applies here.
You should try signalling the thread terminate before calling free, for example;
CleanupThread.Terminate;
if CleanupThread.Waitfor(60000)<>WR_Abandoned then //wait for 60sec for cleanup
CleanupThread.free
else
//do something sensible on timeout or error
But without knowing what, exactly, the cleanup thread is trying to do it is hard to say what could be causing a deadlock. Often these are the result of race conditions, especially if a terminate & waitfor times out, so you need to specify what the thread is doing.
As a hack (and not good practice for multithreading) you can force a thread to exit using the winapi call TERMINATETHREAD (in the Windows unit);
TerminateThread(CleanupThread.handle,0);
As this forces an immediate exit on the thread but also means no thread cleanup is performed - remember that calling TTHREAD.TERMINATE does not guarantee that a thread will exit - this is entirely dependant on your thread code, if something is blocking your thread then it will not terminate in the normal manner. TerminateThread can solve this, at the expense of the code simply stopping where it is with no regard for any resource freeing or what other threads are up to.

Thread scheduling issue with MFC and AfxBeginThread

I'm creating a worker thread in MFC with AfxBeginThread, but the thread is not getting scheduled. Here's the code:
CWinThread* worker = AfxBeginThread(initialUpdateWorkerThread, this);
DWORD dwExitCode = 0;
while(GetExitCodeThread(worker->m_hThread, &dwExitCode))
{
if(dwExitCode != STILL_ACTIVE)
break;
::Sleep(100);
}
When I run this, this loop just livelocks because initialUpdateWorkerThread is never called (I've put break points and message boxes at the top of it) so dwExitCode is always STILL_ACITVE. But if I put in a call to AfxMessageBox before the loop but after AfxBeginThread then the function is called. This makes me think that somehow I'm not calling the right function to get the thread scheduled, but a call to AfxMessageBox causes it to get scheduled.
How can I force the thread to be scheduled? I would think sleep would do that, but in this case it doesn't seem to.
Your worker thread is probably trying to send your main thread a message, but since you aren't processing messages on on the main thread, the worker thread simply waits. You can confirm this by simply breaking into the debugger to see what the worker thread is doing.

Worker thread termination in MFC

What is the correct way to terminate a worker thread if it is taking too long to complete? I've read several articles claming that TerminateThread should be used with extreme caution, but I can't find any viable alternative.
Psudo code:
void CMyDialog::RunThread()
{
CWinThread* pThread; // pointer to thread
DWORD dwWaitResult; // result of waiting for thread
// start thread
pThread = AfxBeginThread(beginThread, this,
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->ResumeThread();
// wait for thread to return
dwWaitResult = ::WaitForSingleObject(pThread->m_hThread, (30 * 1000));
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
delete pThread;
// success, continue
break;
case WAIT_TIMEOUT:
// thread taking too long, terminate it
TerminateThread(pThread->m_hThread, 0);
delete pThread;
break;
} // end switch on wait result
}
UINT CMyDialog::beginThread(LPVOID pParam)
{
// convert parameter back to dialog object and call method
CMyDialog* dlg = (CMyDialog*) pParam;
dlg->readDuration();
return 0;
} // end beginThread
void CMyDialog::readDuration()
{
// call a dll function that may take longer than we are prepared to wait,
// or even hang
} // end readDuration
Is this acceptable? All comments and suggestions gratefully recieved.
I am using MFC/C++ in Visual Studio 2008. Developing on Vista, targeting XP, Vista and 7.
Is unsafe to terminate a thread, as Sanja already mentioned. The typical solution in such cases is to spawn a child process that only role is to host the DLL and call the method(s). You main process will communicate with the child process via some LPC mechanism to pass in the arguments for the DLL method invocation and get back the result. On timeout is perfectly safe to kill the child process, the kernel will reclaim all resources and there will be no in-memory or system object leaks (there could be persisted on-disk leaks, like files left over, though). It is significantly more complicated that just simply calling the DLL (you'll need to come up with the inter-process communication solution) but is the only reliable way.
Its a bad idea to use TerminateThread its not safe and can cause some leaks. You can use events to tell your thread end.
Some useful links
http://www.codeproject.com/KB/threads/Synchronization.aspx
http://msdn.microsoft.com/en-us/library/ms686915(v=vs.85).aspx
Good answer about terminatethread here

Delphi - Help calling threaded dll function from another thread

I'm using Delphi 2006 and have a bit of a problem with an application I'm developing.
I have a form that creates a thread which calls a function that performs a lengthy operation, lets call it LengthyProcess. Inside the LengthyProcess function we also call several Dll functions which also create threads of their own.
The problem that I am having is that if I don't use the Synchronize function of my thread to call LengthyProcess the thread stops responding (the main thread is still responding fine). I don't want to use Synchronize because that means the main thread is waiting for LengthyProcess to finish and therefore defeats the purpose of creating a separate thread.
I have tracked the problem down to a function inside the dll that creates a thread and then calls WaitFor, this is all done using TThread by the way. WaitFor checks to see if the CurrentThreadID is equal to the MainThreadID and if it is then it will call CheckSychronization, and all is fine. So if we use Synchronize then the CurrentThreadID will equal the MainThreadID however if we do not use Synchronize then of course CurrentThreadID <> MainThreadID, and when this happens WaitFor tells the current thread (the thread I created) to wait for the thread created by the DLL and so CheckSynchronization never gets called and my thread ends up waiting forever for the thread created in the dll.
I hope this makes sense, sorry I don't know any better way to explain it. Has anyone else had this issue and knows how to solve it please?
If your secondary thread "stops responding," then I assume it has a message pump. (Otherwise, you need to explain what it stops responding to.) You appear to also wish for the thread to be able to detect when the tertiary thread finishes running. (The "primary" thread here is the VCL thread, which isn't involved at all.)
You tried using WaitFor, but were disappointed when you discovered that it blocks. That's what it has always been designed to do, though. Its behavior in the main thread is where it gets weird, so it's safe to call from the VCL thread even though it was never really meant to be used that way originally.
To process messages and wait for threads to finish running, you need to use one or more of the wait functions from the Windows API. Start with MsgWaitForMultipleObjects. It can wait for various types of kernel handles, including thread handles, but also notify you when messages are available. The idea is that you'll call that function in a loop. When it says messages are available, handle them, and then loop again to continue waiting.
The following is just an outline. You'll want to check the documentation for all the API functions used, and combine that with the rest of the knowledge you have about your own threads.
procedure TSecondaryThread.Execute;
var
ret: DWord;
ThreadHandle: THandle;
Msg: TMsg;
begin
ThreadHandle := TertiaryThread.Handle;
repeat
ret := MsgWaitForMultipleObjects(1, ThreadHandle, False, Infinite, qs_AllEvents);
case ret of
Wait_Object_0: begin
// The thread terminated. Do something about it.
CloseHandle(ThreadHandle);
PostQuitMessage(0);
// Put *something* in the parameter so further calls to MWFMO
// will have a valid handle. May as well use a handle to something
// that will never become signaled so all we'll get are more
// messages. I'm pretty sure you can't pass an empty array of
// handles; there must be at least one, and it must be valid.
ThreadHandle := Self.Handle;
end;
Wait_Object_0 + 1: begin
// At least one message is available. Handle *all* of
// them before calling MsgWaitForMultipleObjects again
while PeekMessage(Msg, 0, 0, 0, pm_Remove) do
case Msg.Message of
wm_Quit: begin
// Do something about terminating the tertiary thread.
// Then stop the message loop and the waiting loop.
Exit;
end;
else begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
end;
Wait_Timeout: Assert(False, 'Infinity has passed');
Wait_Failed: RaiseLastOSError;
else Assert(False, 'Unexpected return value');
end;
until False;
end;
The part about handling all the messages is important. As soon as you call GetMessage, PeekMessage, or WaitMessage, the OS marks all messages in the queue as "old," but MsgWaitForMultipleObjects will only return when there is a "new" message on the queue — one that arrived after the last call to PeekMessage.
HI, Thanks for your reply, yes i realize that my question isn't very clear and somewhat confusing; so i'll try to clarify things a bit, here goes..
All of the threads described below are derived from TThread.
I have a form which starts a thread but does not wait for it. The thread started by the form calls a function that performs a long task.
The function calls another function in a DLL, the function in the DLL starts a thread and waits for it. The thread started by the DLL function calls another function via synchronize.
Form->Starts a thread but does not wait->The thread calls a functions->The function calls a DLL function->The Dll function starts a thread and waits->The thread started by the DLL function calls another function via synchronize i.e Synchronize(UpdateRecords).
The problem is that the call to synchronize never returns because, from what i can see, it has entered some sort of dead lock.
How synchronize works: Synchronize puts the method call into a queue and sets an event, Synchronize then waits for the event to become signaled. When the main thread is idle it will process the method calls that are waiting in the queue, after it has processed a method call it will signal the associated event so that the thread that initiated the synchronization can continue on.
The thread that was started by the form does not use synchronize to call the function that performs the long task, if it does use synchronize then the application does not dead lock, but this defeats the purpose of use a thread for the long process.
I've tracked down the problem, it seems to be that the TApplication object created by the dll is not processing messages and has a handle of 0, how this happened I don't know (I didn't write the DLL, it was written by someone else), but it is a cause of the problem because it will never process the method called queued by synchronize.
I mentioned earlier that if i call the function that performs the long process from my thread using synchronize then the application does not dead lock. This is because the main thread will be responsible for calling the function that performs the long process. So the long process function calls a DLL function which starts another thread and then calls WaitFor. WaitFor checks to see if the current thread is the main thread, and if it is, it processes method calls which have been queued by synchronize, continuously in a loop until the thread the thread that it is waiting for is released (i.e. the method it queued via synchronize gets called and the wait event is signaled).
In WaitFor, if the current thread is not the main thread then WaitFor simply blocks until the thread it is waiting for is released.
Anyway i can't do anything about the application object in the dll because that dll is quite complex and used by a larger system. I guess i can expose a method in the dll which can process the methods in the synchronization queue, i can then call this method from my application while its idle.
Anyway again thanks for your help but i've solved this problem now.
Using the TThread class or even the Application object in a Delphi DLL is extremely unsafe. The RTL and VCL core classes, globals and singleton objects are designed to exist once per process and can't handle the namespace duplication and incomplete initialization in a stadard DLL library.
You may get around it by building with runtime packages (RTL & VCL are enough; you may also build your own with just the system units you reallt need), in the EXE and all DLLs referencing the runtime units (Forms and Classes, especially) - they get single shared namespace and the full EXE initialization sequence this way.
If you can't modify the DLL at all, you may try to set it's Application.Handle, MainThreadID, SyncEvent and WakeMainThread to the corresponding values in the main EXE module - this may work, but it's just as ugly as it looks like and it doesn't cover all edge-cases (the classes and important globals will still be duplicated).

Resources