Using the Thread Pool for Asynchronous Programming

Many applications spend a lot of time doing nothing. Nothing, that is, except waiting for some kind of events or special circumstances to occur. After these events or circumstances have occurred, the application awakens, processes the events and then goes back to sleep. To make these tasks more efficient, .NET uses a thread pool. The following section explores the ThreadPool class and how to use it.

Explaining the WaitCallback Delegate

Similar to the ThreadStart delegate, WaitCallback is a wrapper around the program code that is to be executed by a thread pool:

Listing 9.9 demonstrates the use of a simple thread pool. It queues a work item and then waits for the user to press the Enter key before exiting the program. Because the thread pool uses background threads, removing the line of code that waits for the Enter key to be pressed would cause the program to exit before running the thread pool task. This is what is known as a race condition.

TIP

Just as bad as synchronization issues, race conditions can wreak havoc on your application. Any time you have a thread executing in the background, you need to make sure that one of two things is possible:

If your application attempts to terminate, your thread will force the application to wait until the thread has completed its task successfully.

If the application terminates, your background thread process can trap the ThreadAbort exception and properly dispose of any in-progress work by rolling it back or whatever else needs to be done.

If the background thread fails to handle either of these two cases, your application will be unstable while that thread is running, and will produce inconsistent results every time the application terminates during that thread.

Passing Data to Threads

Occasionally, there is a need for a thread to use data or state from an outside section of code. You could use properties or methods to set the values of class-scope variables, but suppose that the thread method is a static method. If this is the case, the method does not have a pointer to the this variable and therefore does not have access to any class-scope variables. To solve this problem, the ThreadPool constructor takes a WaitCallback delegate as a parameter. As you learned earlier in this section, the WaitCallback delegate takes an object as its only parameter. This enables you to pass any information or state to the ThreadPool as an object that will in turn be passed to the thread method. Listing 9.10 demonstrates how to pass a variable to a ThreadPool worker thread.