While a Mutex is used to prevent simultaneous access (Locking), a Condition Variable is used to signal state changes (Waiting).

1. The Main Concept: Sleep, Don’t Spin

In the previous section, the consumer wasted CPU cycles by repeatedly checking (spinning) if data was ready.

  • The Goal: We want the consumer to put itself to sleep if there is no data.
  • The Wakeup: We want the producer to wake up the consumer specifically when it adds data to the buffer.
2. The New API Functions

Stevens introduces two primary functions here:

  • pthread_cond_wait(cond, mutex): This function puts the calling thread to sleep. Crucially, it takes the mutex as an argument.
    • Action: It atomically unlocks the mutex and puts the thread to sleep.
    • Return: When the thread wakes up (is signaled), it automatically re-acquires the mutex before returning.
  • pthread_cond_signal(cond): Wakes up one thread waiting on the condition variable.
3. The Correct Pattern (Figure 7.6 / 7.7)

This is the standard boilerplate for waiting on a condition in Unix Network Programming. It fixes the logic from the previous section.

// The Consumer Code
Pthread_mutex_lock(&shared.mutex);     // 1. Acquire the lock
 
while (shared.nput <= shared.nval) {   // 2. Check the condition (Loop!)
    Pthread_cond_wait(&shared.cond, &shared.mutex); 
    // 3. unlock + sleep ... [WAITING] ... re-lock
}
 
// 4. We are awake and have the lock. Process data.
process_data();
 
Pthread_mutex_unlock(&shared.mutex);   // 5. Release the lock
4. Critical Technical Details

Stevens highlights two very important technical nuances in this section that often trip up beginners:

A. The “While” Loop vs. “If” Statement

You might be tempted to check the condition with an if statement:

if (shared.nput <= shared.nval) { wait(...); } // DANGEROUS!

Why use while?

  1. Spurious Wakeups: In some implementations, threads might wake up even if no one signaled them. The while loop forces the thread to double-check the condition after waking up.
  2. Intercepted Signals: Even if the producer signals, another thread might “steal” the lock and change the state before the waiting thread gets to run. The loop ensures the condition is still true.
B. Atomicity of pthread_cond_wait

Why does the wait function need the mutex?

  • If you unlocked the mutex before calling wait, there would be a tiny gap between the unlock and the sleep.
  • If the producer sent a signal during that exact gap, the signal would be lost (because you aren’t asleep yet). The consumer would then go to sleep and never wake up.
  • pthread_cond_wait handles the unlock-and-sleep sequence atomically to prevent this “Lost Wakeup” problem.