Safely Stopping Threads

Please don’t kill your thread…

.

Environment: Win32, VC++ 5.0-6.0, Win 2000, NT 4.0, Win95/98

Preface

Some days ago I read the article "A Generic C++ Thread Class" published by Arun N Kumar on the codeguru Web site. I was curious about his ideas because some years ago I also wrote a little C++ thread class. Reading the article and looking at the code I found some good ideas but I also had some doubts and decided to give a comment about this article. I soon realized that I had too much to say, so I decided to write anarticle. I searched for my code, did some cleanup, and started writing. I hope you enjoy it!

My solution…

The first problem you encounter if you think about a thread class is the fact that all API functions used to create a thread want to have a pointer to a function. So passing a pointer to a member function is not possible cause a member function has always an implicit "this" pointer in their function signature. Therefore you have to use the following workaround: Add a static function to your class, pass the address of this static function to the API. The static function itself then has to call a member function which contains the code to execute the thread. To start a thread I choosed the API _beginthreadex() cause this method initializes certain C run-time library variables. This is important only if you use the C run-time library in your threads.

If the start of a thread works you will encounter another problem: "how can I stop it ?". I have seen a lot of examples where programmers are using the API TerminateThread() to stop the thread execution. This is not a good idea! Why? TerminateThread() is like killing your thread! The thread doesn’t get the chance to cleanup any used resources (for example file handles, network sockets). To be detailed I copied the following statements from the MSDN Library:

TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.

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 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 for my understanding, TerminateThread() is not a good choice for a generic thread class.

My solution to stop a thread is more polite. My Thread class owns an event-object. An event-object works somehow like a traffic light it can be signaled or not. If I want to stop my running thread I trigger the event to be signaled. This is done in the Stop() method of my thread class.

Setting an event to signaled state is one half of the job. The second is that the thread-function has to check this event-object from time. If the event is signaled the thread stops execution of the thread code, do necessary clean-ups and return giving the thread exit-code.

To check an event-object you use the function WaitForSingleObject() in the window-system. This call is wrapped in the method AThread::isStopEventSignaled(). Usually a worker thread has a loop which executes the thread code for some time. So a good place to check the event-object is the loop-condition.

The class

This is the layout of my class AThread (the A stand for "another"):

class AThread
{
public:
AThread();
virtual ~AThread();
bool Start();
bool isRunning(DWORD dwTimeOut = 50) const;
bool Stop();
DWORD getThreadID() const;

protected:
virtual unsigned ThreadFunction() = 0;
static unsigned __stdcall ThreadStarter(void* PtrToInstance);
bool isStopEventSignaled(DWORD dwTimeOut = 10) const;

//attributes
protected:
unsigned m_ThreadID; //holds the threadID
HANDLE m_hThread; //holds the HANDLE of the created thread
HANDLE m_hStopEvent; // holds the handle of the event-object
// to signal the thread that he has to stop
};

The described workaround with the static function is represented by the methods ThreadStarter() and ThreadFunction(). The address of ThreadStarter() is passed to _beginthreadex(). The implementation of ThreadStarter() just delegates the call to method ThreadFunction(), which contains the thread code. Please notice that ThreadFunction() is abstract you have to provide an implementation in a derived class.

The methods
























Method name


Description


Start()


call this method to start thread execution


Stop()


call this method to stop thread execution. This method triggers the event-object m_hStopEvent.


isRunning()


gives information if the thread is currently running or not



getThreadID()


returns the thread identifier of a running thread


IsStopEventSignaled()


Checks the stop-event using WaitForSingleObject() if it’s signaled or not. Returns false if the event is signaled. Makes implementation of ThreadFunction() a little bit easier


getExitCode()


call this method to get the exit code of the thread. If the thread is running, the value STILL_ACTIVE will be returned

Example:

I created the class ExampleThread to show how this works (see zip-file). This looks like:

class ExampleThread : public AThread
{
public:
ExampleThread();
virtual ~ExampleThread();

//overwritten abstract method
unsigned ThreadFunction();
};

the overwritten method ThreadFunction() contains the thread-code which is quite simple:

unsigned ExampleThread::ThreadFunction()
{
//while loop will execute till the stop-event is signaled
while(isStopEventSignaled() == false) {
printf(“<%i>”, m_ThreadID);
}

//here is the place to cleanup/free resources
printf(“ExampleThread::ThreadFunction() after while loopn”);

return 0; //return exit-code of thread
}

the while loop executes until isStopEventSignaled() returns false (the event-object is signaled). The code inside the loop just prints out the thread-id to the console window. Place code needed for cleanup after the while-loop().

The usage of the class looks like this (see main() function in the zip-archive):

ExampleThread myThread;
myThread.Start();
// The thread-code inside ExampleThread:: ThreadFunction()
// is now running


DWORD ID = myThread.getThreadID();

bool bIsRunning = myThread.isRunning(); //will return “true”

myThread.Stop();

bool bIsRunning = myThread.isRunning(); //will return “false” because
//the thread is stopped

DWORD dwExitCode = myThread.getExitCode(); //get the exit code
//of the thread

I have provided another example in the zip-archive which makes more fun (see class BounceCharThread). The code inside BounceCharThread::ThreadFunction() moves around a character inside the console window (this code was copied from a MSDN thread example). If a character reaches the border of the window, you will hear a beep. The main() function in the project HL_Thread (see zip-archive) creates 10 instances of the class BounceCharThread and call for each instance the Start() method. Therefore you will see 10 characters moving around in the console window. Have fun !

Conclusion

In this article I introduced a thread class that uses a polite (and safe) way to stop the execution of a thread. I hope I will see less code in the future using the API TerminateThread()!

As usual, if you have any doubts, questions, ideas, bugs please make a comment.
Thank you !

Downloads

Download demo project – 34 Kb

More by Author

Must Read