Abstract
A Condition Variable (CV) is a memoryless synchronization primitive that enables a thread to sleep inside a critical section by atomically releasing an associated lock and placing the thread on a wait queue. Used in conjunction with a lock, CVs allow threads to wait for complex state conditions to become true without holding the lock while sleeping.
- Category: High-Level Synchronization Mechanics
- Core Operations:
wait(cv, lock),signal(cv),broadcast(cv).- Key Invariant: Memoryless (signals delivered with no waiters present are lost).
- Dominant Standard: Mesa Semantics (requires checking conditions inside a
whileloop).
1. Why Condition Variables?
When a thread enters a critical section protected by a lock but discovers that a required resource condition is not met (e.g., the input buffer is empty), it must wait.
- Why not keep holding the lock and sleep? If the thread sleeps while holding the lock, no other thread can enter the critical section to produce the missing resource Deadlock.
- The CV Solution:
wait(cv, lock)atomically releases the lock and puts the calling thread to sleep in a single indivisible step.
2. Condition Variable API & Operations
A Condition Variable is always associated with an explicit Mutex Lock:
wait(cv, lock): Atomically releaseslock, puts the calling thread to sleep oncv’s queue, and blocks. When awakened, it re-acquireslockbefore returning.signal(cv): Awakens one thread waiting oncv’s queue (if any). If no threads are waiting, the signal is discarded (memoryless).broadcast(cv): Awakens all threads currently waiting oncv’s queue.
Memoryless Property vs. Semaphores
Unlike semaphores, Condition Variables have no history counter. Calling
signal()when no threads are currently waiting does nothing; the signal is permanently lost.
3. Signaling Semantics: Mesa vs. Hoare
What happens immediately after Thread calls signal(cv) to wake Thread ?
1. Mesa Semantics (Production Standard)
- The signaler thread retains the lock and continues executing.
- The woken thread is moved to the Ready Queue.
- Impact: By the time the woken thread actually re-acquires the lock and runs, another thread may have entered the critical section and altered the condition!
- Mandatory Code Pattern: Must re-evaluate condition using a
whileloop:
// Correct for Mesa Semantics
acquire(&lock);
while (condition_is_not_met) { // RE-CHECK CONDITION!
wait(&cond_var, &lock);
}
/* Execute Critical Section */
release(&lock);
2. Hoare Semantics
- The signaler thread immediately yields the lock to the woken thread, which runs instantly.
- Impact: The condition is guaranteed to hold, so an
ifstatement suffices. However, implementation complexity is extremely high.

4. Common Pitfalls when Using Condition Variables
Pitfall 1: Checking CVs Without a Separate Flag
CVs hold no state. You cannot test if a CV is “true”. You must maintain a separate shared state variable (e.g., count or flag) guarded by the lock.
Pitfall 2: Releasing the Lock Before Calling wait()
Releasing the lock before calling wait() opens a race window where another thread can modify the condition and issue a signal() before the waiting thread actually goes to sleep Lost Wakeup Bug.
Pitfall 3: Using if Instead of while Under Mesa Semantics
Using if (condition) under Mesa semantics allows “spurious wakeups” or race conditions where a woken thread acts on an invalid condition. Always use a while loop around wait().