Questions: Condition Variables: Usage Patterns and Pitfalls
5 questions to test your understanding
Score: 0 / 5
Question 1 Multiple Choice
A thread wakes from a condition variable wait() call and finds the condition it was waiting for is still false. In a correctly written program, what should happen next?
AThe thread should proceed anyway — if it was signaled, the condition must be true
BThe thread should release the lock and terminate, since the wakeup was erroneous
CThe thread should re-check the condition in its while loop and call wait() again
DThis cannot happen if the signaling thread holds the lock when it calls signal()
Spurious wakeups and barging can cause a thread to wake even when the condition is false. The OS may wake a thread for implementation reasons unrelated to any signal(), or a third 'barging' thread can acquire the lock between the signal and the waiter reacquiring it, changing the condition back to false. The while-loop pattern handles all of these: the thread re-checks and calls wait() again if still false. Using `if` instead of `while` is a classic concurrency bug because it assumes wakeup implies the condition holds.
Question 2 Multiple Choice
A bounded buffer uses a single condition variable shared by both producers (waiting when full) and consumers (waiting when empty). A producer adds an item and calls signal(). What could go wrong?
ANothing — signal() correctly wakes one waiting thread, which will then check its condition
BAnother producer could be woken instead of a consumer, find the buffer still full, and go back to sleep without notifying any consumer
CThe signaled thread will always be a consumer because signal() uses FIFO ordering
Dsignal() is invalid unless called with the lock held, causing undefined behavior
When producers and consumers share one condition variable, signal() wakes one thread — but it might wake another producer. That producer checks whether the buffer is not-full (it still is, since an item was just added), goes back to sleep, and no consumer is ever woken. The item sits in the buffer forever. The fix is either separate condition variables (one per condition) or broadcast() so all waiters recheck. This illustrates why signal() requires careful reasoning about which waiter gets woken.
Question 3 True / False
Using `if (!condition) wait(cv, lock)` instead of `while (!condition) wait(cv, lock)` is safe as long as the signaling thread typically holds the lock when it calls signal().
TTrue
FFalse
Answer: False
Holding the lock during signal() is necessary but not sufficient to make `if` safe. The problem is barging: after the signaling thread calls signal() and releases the lock, a third thread can acquire the lock before the waiting thread does, and change the condition back to false. The waiting thread then wakes with the condition false — a bug. Additionally, POSIX explicitly permits spurious wakeups (wakeups with no corresponding signal()) for implementation reasons, making `while` necessary regardless of lock discipline.
Question 4 True / False
Using broadcast() in place of signal() is always correct, even if it causes unnecessary wakeups.
TTrue
FFalse
Answer: True
broadcast() wakes all waiting threads; each then re-checks its condition in the while loop and goes back to sleep if the condition is not satisfied. This is always correct — it may waste CPU cycles on unnecessary wakeups, but it never leaves a thread blocked when it could make progress. signal() is an optimization that requires careful reasoning about which waiter will be woken; broadcast() is the safe default when in doubt.
Question 5 Short Answer
Explain what 'barging' is in the context of condition variables, and why it requires waits to be in a while loop rather than an if statement.
Think about your answer, then reveal below.
Model answer: Barging occurs when a third thread acquires the mutex in the window between a signal being sent and the waiting thread reacquiring the lock. The waiting thread was legitimately woken, but before it could proceed, the barging thread grabbed the lock first — potentially consuming the resource or changing the condition back to false. When the original waiting thread finally gets the lock, the condition may no longer hold. A while loop handles this: the woken thread re-checks the condition and waits again if it's false, regardless of whether barging, spurious wakeups, or a legitimate signal caused the wakeup.
Barging is not a bug in the signaling code — it's an inherent property of lock acquisition in most threading implementations. Correctness requires the waiting thread to always re-check rather than trust that a wakeup implies the condition is true.