Condition Variables in C++ Multithreading

Last Updated : 5 Jun, 2026

Condition variables are synchronization primitives in C++ that allow threads to wait for a specific condition to become true before continuing execution. They are commonly used in multithreaded programs to coordinate communication between threads and avoid unnecessary busy waiting.

  • Defined by the std::condition_variable class in the <condition_variable> header.
  • Used together with mutexes to safely synchronize access to shared resources.
  • Allows one thread to wait while another thread signals that a task or resource is ready.
  • Commonly used in producer-consumer, sender-receiver, and task scheduling scenarios.

Prerequisite: C++ Multithreading, Mutex in C++.

Syntax of std::condition_variable

std::condition_variable variable_name;

After that, we use the associated method for different operations.

Condition Variable Methods

The std::condition_variable methods contain some member methods to provide the basic functionalities. Some of these are:

FunctionDescription
wait()This function tells the current thread to wait till the condition variable is notified.
wait_for()Suspends the current thread for a specified relative time duration or until the condition variable is notified, whichever occurs first.
wait_until()This function is similar to the wait_for() but here, the time duration is defined as the absolute time.
notify_one()This function notifies one of the waiting threads that the shared resource is free to access. The thread selection is random.
notify_all()                  This function notifies all of the threads.

Example: Program to Illustrate the Use of Condition Variable

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

using namespace std;

// mutex to block threads
mutex mtx;
condition_variable cv;

// function to avoid spurios wakeup
bool data_ready = false;

// producer function working as sender
void producer()
{
    // Simulate data production
    this_thread::sleep_for(chrono::seconds(2));

    // lock release
    lock_guard<mutex> lock(mtx);

    // variable to avoid spurious wakeup
    data_ready = true;

    // logging notification to console
    cout << "Data Produced!" << endl;

    // notify consumer when done
    cv.notify_one();
}

// consumer that will consume what producer has produced
// working as reciever
void consumer()
{
    // locking
    unique_lock<mutex> lock(mtx);

    // waiting
    cv.wait(lock, [] { return data_ready; });

    cout << "Data consumed!" << endl;
}

// drive code
int main()
{
    thread consumer_thread(consumer);
    thread producer_thread(producer);

    consumer_thread.join();
    producer_thread.join();

        return 0;
}


Output

Data Produced!
Data consumed!

Explanation

  • The producer thread simulates data generation by sleeping for two seconds.
  • After producing the data, it acquires the mutex, sets data_ready to true, and calls notify_one().
  • The consumer thread acquires the mutex and waits on the condition variable using wait().
  • The predicate data_ready prevents the consumer from proceeding before the data is available.
  • Once notified, the consumer thread resumes execution and consumes the produced data.

Common Issues with Condition Variables

While condition variables are useful for thread synchronization, improper usage can lead to certain issues:

  • Spurious Wakeup: A waiting thread may wake up without a notification.
  • Lost Wakeup: A thread may miss a notification if it has not started waiting yet.
  • Incorrect Predicate Usage: Failing to check a condition after waking up can lead to incorrect behavior.
  • Deadlocks: Incorrect locking and waiting logic can cause threads to block indefinitely.

Purpose of Condition Variables

Condition variables help coordinate the execution of multiple threads by allowing a thread to wait until a specific condition becomes true.

  • Allow threads to wait for a condition without continuously checking it.
  • Eliminate busy waiting, reducing unnecessary CPU usage.
  • Enable efficient communication between threads.
  • Work with mutexes to safely synchronize access to shared resources.
  • Commonly used in producer-consumer, sender-receiver, and task synchronization scenarios.
Comment