ReviseAlgo Logo

Concurrency

Condition Variables

Coordinate threads using std::condition_variable to wait for state changes without active busy-waiting.

Interview: Mechanics of spurious wakeups, why a predicate lambda is required, and unique_lock association.

Last Updated: June 13, 2026 9 min read

A Condition Variable allows threads to suspend execution until they are notified of a state change. This prevents polling loops, saving CPU cycles.

Wait Predicate

Always supply a boolean condition check to wait() to prevent issues caused by spurious wakeups.

std::unique_lock

Requires std::unique_lock because the variable unlocks and locks the mutex internally during wait cycles.

Notification

Use notify_one() to wake a single waiting thread, or notify_all() to wake all of them.

Spurious Wakeups

Under certain OS implementations, a thread waiting on a condition variable can wake up without receiving a notification. This is called a spurious wakeup.

Preventative Action

To prevent this, you should always pass a verification predicate to the wait() call: cv.wait(lock, []{ return isReady; }); This forces the thread to re-verify the state and go back to sleep if the condition has not actually been met.

Code Walkthrough

A simple Producer-Consumer coordinate signal loop using a condition variable.

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex g_mutex; std::condition_variable g_cv; bool g_dataReady = false;

void consumer() { std::unique_lock<std::mutex> lock(g_mutex);

// Wait until dataReady is true, handling spurious wakeups automatically g_cv.wait(lock, [] { return g_dataReady; });

std::cout << "Consumer: Data processed successfully!\n"; }

void producer() { { std::lock_guard<std::mutex> lock(g_mutex); g_dataReady = true; std::cout << "Producer: Data is prepared.\n"; } g_cv.notify_one(); // Wake up the consumer thread }

int main() { std::thread t1(consumer); std::thread t2(producer); t1.join(); t2.join(); return 0; }

Interview-Relevant Information

Q: Why does std::condition_variable require std::unique_lock instead of std::lock_guard?
Answer: When a thread calls wait(), the condition variable must release the associated mutex to let other threads (like the producer) acquire it and update the state. Once notified, the condition variable re-acquires the mutex before returning. std::unique_lock supports this manual locking and unlocking behavior, whereas std::lock_guard does not.

Q: What is a spurious wakeup, and how do you prevent it?
Answer: A spurious wakeup is when a thread wakes up from a waiting state without a notification signal. You prevent this by using a loop or passing a predicate function to wait(). The predicate checks the shared state flag, forcing the thread back to sleep if the signal is false.

Quick Checklist

Did you pass a predicate lambda to wait()? Did you use std::unique_lock? If yes, your condition variable usage is correct.

Use Cases

Implementing thread-safe task dispatcher queues (Producer-Consumer pattern).

Suspending worker threads until connection handshakes or startup steps are complete.

Common Mistakes

Calling wait() without a verification predicate, leaving the thread vulnerable to spurious wakeups.

Updating the state flag without holding the associated mutex, causing race conditions with the waiting thread.