[Previous] [Next]

Chapter 17

Threads and Thread Synchronization

In the Microsoft Win32 environment, every running application constitutes a process and every process contains one or more threads of execution. A thread is a path of execution through a program's code, plus a set of resources (stack, register state, and so on) assigned by the operating system.

A fundamental difference between 16-bit and 32-bit versions of Microsoft Windows is that 32-bit Windows doesn't limit its applications to just one thread each. A process in a 32-bit Windows application begins its life as a single thread, but that thread can spawn additional threads. A preemptive scheduler in the operating system kernel divides CPU time among active threads so that they appear to run simultaneously. Threads are ideal for performing tasks in the background while processing user input in the foreground. They can also play more visible roles by creating windows and processing messages to those windows, just as the primary thread processes messages sent to an application's main window.

Multithreading isn't for everyone. Multithreaded applications are difficult to write and debug because the parallelism of concurrently running threads adds an extra layer of complexity to a program's code. Used properly, however, multiple threads can dramatically improve an application's responsiveness. A word processor that does its spell checking in a dedicated thread, for example, can continue to process messages in the primary thread and allow the user to continue to work while the spelling checker runs its course. What makes writing a threaded spelling checker difficult is that the spell checking thread will invariably have to synchronize its actions with other threads in the application. Most programmers have been conditioned to think about their code in synchronous terms—function A calls function B, function B performs some task and returns to A, and so on. But threads are asynchronous by nature. In a multithreaded application, you have to think about what happens if, say, two threads call function B at the same time or one thread reads a variable while another writes it. If function A launches function B in a separate thread, you also must anticipate the problems that could occur if function A continues to run while function B executes. For example, it's common to pass the address of a variable created on the stack in function A to function B for processing. But if function B is in another thread, the variable might no longer exist when function B gets around to accessing it. Even the most innocent-looking code can be fatally flawed when it involves two different threads.

MFC encapsulates threads of execution in the CWinThread class. It also encapsulates events, mutexes, and other Win32 thread synchronization objects in easy-to-use C++ classes. Does MFC make multithreading easier? Not exactly. Developers who have written multithreaded Windows applications in C are often surprised to learn that MFC adds complexities all its own. The key to writing multithreaded programs in MFC is having a keen understanding of what you're doing and knowing where the trouble spots are. This chapter will help you do both.

The CHM file was converted to HTML by chm2web software.