[Return to Bookshelf] [Contents] [Previous Section] [Next Section] [Index] [Help]


2.3.2 Condition Variables

A condition variable allows a thread to block its own execution until some shared data reaches a particular state. A condition variable is a synchronization object used in conjunction with a mutex. A mutex controls access to shared data; a condition variable allows threads to wait for that data to enter a defined state. The state is defined by a Boolean expression called a predicate. A predicate may be a Boolean variable in the shared data or the predicate may be indirect; testing whether a counter has reached a certain value, or whether a queue is empty. Each predicate should have its own unique condition variable. Sharing a single condition variable between more than one predicate can introduce inefficiency or errors unless you use extreme care.

Cooperating threads test the predicate and wait on the condition variable if the predicate is not in the desired state. For example, one thread in a program produces work-to-do packets and another thread consumes these packets (does the work). If there are no work- to-do packets when the consumer thread checks, that thread waits on a work-to-do condition variable. When the producer thread produces a packet, it signals the work-to-do condition variable.

You must associate a mutex with a condition variable. A thread locks a mutex for some shared data and then tests the relevant predicate. If it is not in the proper state, the thread waits on a condition variable associated with the predicate. Waiting on the condition variable automatically unlocks the mutex. It is essential that the mutex be unlocked because another thread needs to acquire the mutex in order to put the data in the state required by the waiting thread. When the thread that acquires the mutex puts the data in the appropriate state, it wakes a waiting thread by signaling the condition variable. One thread comes out of its wait state with the mutex locked (the condition wait relocks the mutex before returning from the thread). Other threads waiting on the condition variable remain blocked.

It is important to wait on the condition variable and evaluate the predicate in a while loop. This ensures that the program will check the predicate after it returns from the condition wait. Note that threads are asynchronous. Another thread might consume the state before an awakened thread can run. Also, the test protects against spurious wakes that might happen and provides clearer program documentation.

For example, a Thread A may need to wait for a Thread B to finish a Task X before Thread A proceeds to execute a Task Y. Thread B can tell Thread A that it has finished Task X by putting a true or false value in a shared variable (the predicate). When Thread A is ready to execute Task Y, it looks at the shared variable to see if Thread B is finished (see Figure 2-2).

Figure 2-2 Thread A Waits on Condition Ready

First, Thread A locks the mutex named mutex_ready that is associated with the shared variable named ready. Then it reads the value in ready. This test is called the predicate. If the predicate indicates that Thread B has finished Task X, then Thread A can unlock the mutex and proceed with Task Y. If the predicate indicates that Thread B has not yet finished Task X, however, then Thread A waits for the predicate to change by calling the pthread_cond_wait routine. This automatically unlocks the mutex, allowing Thread B to lock the mutex when it has finished Task X. Thread B updates the shared data (predicate) to the state Thread A is waiting for and signals the condition variable by calling the pthread_cond_signal routine (see Figure 2-3).

Figure 2-3 Thread B Signals Condition Ready

Thread B releases its lock on the shared variable's mutex. As a result of the signal, Thread A wakes up, implicitly regaining its lock on the condition variable's mutex. It then verifies that the predicate is in the correct state, and proceeds to execute Task Y (see Figure 2-4).

Figure 2-4 Thread A Wakes and Proceeds

Note that although the condition variable is used for communication among threads, the communication is anonymous. Thread B does not necessarily know that Thread A is waiting on the condition variable that Thread B signals and Thread A does not know that it was Thread B that awakened it from its wait on the condition variable.

You can use the pthread_cond_init routine to initialize a condition variable. To create condition variables as part of your program's one-time initialization code, see Section 2.4. You can also statically initialize condition variables using one of the macros provided in .

Use the pthread_cond_wait routine to cause a thread to wait until the condition is signaled or broadcasted. These routines specify a condition variable and a mutex that you have locked. (If you have not locked the mutex, the results of pthread_cond_wait are unpredictable.) These routines automatically unlock the mutex and cause the calling thread to wait on the condition variable until another thread calls one of the following routines:

If a thread signals or broadcasts on a condition variable and there are no threads waiting at that time, the signal or broadcast has no effect. The next thread to wait on that condition variable blocks until the next signal or broadcast. (The pthread_cond_signal_int_np routine creates a pending wake condition, which causes the next wait on the condition variable to complete immediately.)

If you want to limit the time that a thread waits for a condition to be signaled or broadcasted, use the pthread_cond_timedwait routine. This routine specifies the condition variable, mutex, and absolute time at which the wait should expire if the condition variable has not been signaled or broadcasted.

You can destroy a condition variable and reclaim its storage by calling the pthread_cond_destroy routine. Use one of these routines only after the condition variable is no longer needed by any thread. A condition variable cannot be deleted while one or more threads are waiting on it.



[Return to Bookshelf] [Contents] [Previous Section] [Next Section] [Index] [Help]