0
0
CppHow-ToBeginner · 4 min read

How to Use condition_variable in C++: Simple Guide with Example

In C++, std::condition_variable is used to block a thread until notified by another thread, enabling thread synchronization. You use it with a std::unique_lock and call wait() to pause and notify_one() or notify_all() to resume waiting threads.
📐

Syntax

The basic syntax involves creating a std::condition_variable object, a std::mutex, and a shared condition variable. Threads use wait() with a std::unique_lock to wait, and other threads call notify_one() or notify_all() to wake waiting threads.

  • std::condition_variable cv; — declares the condition variable.
  • std::mutex mtx; — mutex to protect shared data.
  • std::unique_lock lock(mtx); — locks the mutex for waiting.
  • cv.wait(lock, predicate); — waits until predicate is true.
  • cv.notify_one(); — wakes one waiting thread.
  • cv.notify_all(); — wakes all waiting threads.
cpp
std::condition_variable cv;
std::mutex mtx;

// Thread waiting
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return condition; });

// Thread notifying
cv.notify_one(); // or cv.notify_all();
💻

Example

This example shows one thread waiting for a flag to become true, while another thread sets the flag and notifies the waiting thread.

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

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void waiting_thread() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });
    std::cout << "Thread resumed: ready is true\n";
}

void notifying_thread() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
        std::cout << "Flag set to true, notifying...\n";
    }
    cv.notify_one();
}

int main() {
    std::thread t1(waiting_thread);
    std::thread t2(notifying_thread);
    t1.join();
    t2.join();
    return 0;
}
Output
Flag set to true, notifying... Thread resumed: ready is true
⚠️

Common Pitfalls

Common mistakes include:

  • Not using a std::unique_lock with wait(); a std::lock_guard won't work.
  • Not protecting the shared condition variable with a mutex, causing race conditions.
  • Calling notify_one() or notify_all() without locking the mutex first.
  • Not using the predicate version of wait(), which can cause spurious wakeups and incorrect behavior.
cpp
# Wrong: Using lock_guard instead of unique_lock
std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void wrong_wait() {
    std::lock_guard<std::mutex> lock(mtx); // wrong
    cv.wait(lock, []{ return ready; }); // error: wait needs unique_lock
}

// Correct way:
void correct_wait() {
    std::unique_lock<std::mutex> lock(mtx); // correct
    cv.wait(lock, []{ return ready; });
}
📊

Quick Reference

FunctionDescription
std::condition_variable cv;Declare a condition variable
cv.wait(lock);Wait until notified (lock is unique_lock)
cv.wait(lock, predicate);Wait until predicate returns true
cv.notify_one();Wake one waiting thread
cv.notify_all();Wake all waiting threads
std::mutex mtx;Mutex to protect shared data
std::unique_lock lock(mtx);Lock mutex for waiting

Key Takeaways

Use std::condition_variable with std::unique_lock to wait and notify threads safely.
Always protect shared data with a mutex when using condition_variable.
Use the predicate version of wait() to avoid spurious wakeups.
Call notify_one() or notify_all() after modifying the shared condition under mutex lock.
Never use std::lock_guard with wait(); it requires std::unique_lock.