Adi Levin's Blog for programmers

September 19, 2009

Ending a thread

Filed under: Multithreading — Adi Levin @ 1:59 pm
Tags: , , ,

There are three ways to end a thread: Return from the thread function, call ExitThread from within the thread, and call TerminateThreadfrom any thread. The best thing to do is return from the thread function. This way, you guarantee that all destructors of automatic variables have been called, and that thread termination is done properly.

TerminateThread – never use it!

BOOL WINAPI TerminateThread(
  __inout  HANDLE hThread,
  __in     DWORD dwExitCode
);

Some programmers make the mistake of waiting with a timeout until a thread is finished, and then kill it using TerminateThread in case of timeout. Don’t do that! TerminateThread terminates the thread immediately without doing the proper clean-up and notifications. It doesn’t free the stack (1Mb leak), it doesn’t free owned critical sections, it doesn’t call the DLL entry functions to notify them that the thread is being detached. Of course, it doesn’t give the thread a chance to free objects allocated on the heap.

The result is a potential deadlock, and the worst thing is that it happens with low probability, so there is a good chance that software testing will not detect it, and your customer will be the first to encounter it. Why a potential deadlock? Because certain library functions (such as malloc, free and MFC functions), use critical sections to synchronize access of threads within the process to certain resources (such as the heap). This means that whenever you call malloc you are waiting for a critical section to be released. But if you called TerminateThread while that thread owned that critical section, the wait will result in a dead-lock.

In fact, there is no justification to using TerminateThread. It is only safe to use when you control exactly what that thread is doing (e.g. you know that it doesn’t do heap allocation, and it is not inside a critical section). But if you are the programmer of that thread’s function, then why not write code that returns safely from the thread function upon some event or flag, or calls ExitThread when needed?

ExitThread – use it with care!

ExitThread can only be called from within the thread which you want to exit. It frees the stack and calls the entry point of each DLL in the process to notify it that the thread is being detached. However, it does not perform destruction of C++ objects as done when returning from a function. This is why you have to use it with care.

In certain situations, it make sense to use ExitThread for the purpose of simplifying the code. For example, if the thread is in alertable state (i.e. waits for APC functions), other threads can queue an APC function that calls ExitThread, thereby causing the thread to exit.

The best way: Returning from the thread function

The best way to write a thread function is to design it so that another thread (the main thread, or the thread that is managing the worker threads), can cause it to end in an orderly fashion.

 For example, if you run a loop with many iterations, check the value of a certain flag in each iteration, and return if it is non-zero. Other threads can change the value of that flag when they want your thread to finish.

 

If your thread waits for some object to be signaled, using WaitForSingleObject(obj,…), and you want to be able to stop the wait from another thread, replace the wait function by WaitForMultipleObjects, and wait for obj and for an event that can be signaled by another thread, when termination is needed.

More generally, in any point in the code where you want to be able to interrupt the operation of the thread and cause it to exit, you should place the appropriate code.

Advertisements

September 12, 2009

Windows Thread Pool

Filed under: Multithreading — Adi Levin @ 2:13 pm
Tags: ,

As an alternative to creating threads and explicitly assigning tasks to threads, Windows offers a collection of API functions that manage a pool of threads. The idea is that the operating system will be responsible for the creation and deletion of threads. To execute a certain function on a thread from the thread pool, the programmer doesn’t need to identify the specific thread. The system will automatically manage the queue of functions that should be invoked and the collection (pool) of threads that are used to invoke them.

Significant changes in the Windows API between XP and Vista

In my own experience, the API that is available in Windows XP (now called the legacy thread pool) does not provide enough control over the way that tasks are assigned to threads. In particular, there is only one thread pool, and tasks are processed in a first-in-first-out order. This means that higher priority tasks that arrive later have to wait until low-priority tasks finish their work. Also, the legacy thread pool is confusing because there are two kinds of threads IO and non-IO.

It seems that the guys at Microsoft understood the problems of the legacy thread pool. In Windows Vista and in Windows Server 2008, the thread pool API is significantly improved. In particular, you can construct a number of thread pools, and there is no longer a separation between IO and non-IO threads. Still, if you’re writing code that’s supposed to run on Windows XP, you can’t use the new API.

My personal opinion

I am not a fan of the Windows thread pool. In my own multithreading experience, I started by using the thread pool, because it seemed the easiest thing to do. After a while, I discovered the limitations of the legacy thread pool, and decided I had to switch to a different multithreading API, or to implement my own thread-pool (which I did). Now, even though the new thread pool API seems better, I can’t use it because the programs I write are targeted to both Windows XP and Windows Vista.

I think that some sort of thread pool is a must, but I would not recommend using Windows API for it, because of the above reasons and because other, portable, solutions exist – OpenMP and the Intel Thread Building Blocks. If really can’t stand the idea of using third party libraries, consider implementing your own thread pool mechanism.

Links

An article on the new Thread Pool API – http://msdn.microsoft.com/en-us/magazine/cc163327.aspx

MSDN article on new and legacy API – http://msdn.microsoft.com/en-us/library/ms686766(VS.85).aspx

Create a free website or blog at WordPress.com.