Synchronizing Threads

How do you prevent thread collisions? Win32 provides powerful synchronization objects to coordinate the work of multiple threads. Each synchronization object is in either a signaled or nonsignaled state. Signaled means that the object is available. Nonsignaled means that it is unavailable or in use by another process or thread.

The most common use for synchronization objects is to protect resources, like global variables, that are shared among multiple threads. Synchronization objects let you serialize access and ensure that one thread does not start reading the value of a character array, for example, until the other thread has finished writing to it.

The simplest form of mutual exclusion is a Critical Section. Critical Sections provide mutual exclusion between multiple threads within a single process. Only one thread can get exclusive access to the Critical Section by using EnterCriticalSection. All of the other threads are held in an efficient wait state, not scheduled by the operating system, until they are able to get access to the Critical Section. When they are finished, they call LeaveCriticalSection and let another thread get in. Critical Sections are global variables whose value is set by the operating system (Kernel) rather than by the user. Mutexes are similar to Critical Sections, but provide mutual exclusion across processes on the same machine. Semaphores allow you to throttle the number of users accessing a particular resource. When the semaphore is created, the maximum number of simultaneous users is specified. When the user calls WaitForSingleObject and the usage count is less than the maximum, the system decrements the usage count and wakes up the thread. Critical Sections, Mutexes, and Semaphores are generally used to control access to data. Events are used to signal that some task has been completed or a task is ready to be started. The following illustration shows these concepts.