Concurrency

C++ Condition Variables

Condition Variables

C++ condition variables use std::condition_variable for synchronization.

Introduction to Condition Variables

Condition variables in C++ are synchronization primitives that enable threads to wait until a particular condition is met. They work with std::mutex to manage the synchronization of shared resources. The std::condition_variable class is part of the C++ standard library and is essential in multi-threaded programming.

Basic Usage of std::condition_variable

The primary operations for a condition variable are wait, notify_one, and notify_all. The wait operation blocks the current thread until the condition variable is notified. The notify_one operation wakes up one waiting thread, and notify_all wakes up all waiting threads.

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

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

void print_id(int id) {
    std::unique_lock<std::mutex> lck(mtx);
    while (!ready) cv.wait(lck);
    // Proceed once 'ready' is true
    std::cout << "Thread " << id << std::endl;
}

void set_ready() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;
    cv.notify_all();
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(print_id, i);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    set_ready();

    for (auto& th : threads) th.join();
    return 0;
}

Understanding the Wait Function

The wait function is crucial for condition variables. It releases the mutex while the thread is waiting and automatically re-acquires it once the thread is notified and the wait condition is satisfied. This is typically used in a loop to check the condition repeatedly.

Using notify_one and notify_all

The notify_one function wakes up a single waiting thread, which can be useful when only one thread should proceed. In contrast, notify_all resumes all waiting threads, which is useful when multiple threads need to proceed after a condition is met. Choosing between these depends on the specific needs of your application.

Best Practices and Considerations

  • Always use a std::unique_lock with a condition variable. This is necessary for the wait function to work properly.
  • Be cautious of spurious wakeups, which are false wakeups that can occur. Always use a loop to check the condition.
  • Avoid using notify_all if only one thread needs to be notified, as it can lead to inefficiencies.
  • Ensure the condition variable and the corresponding mutex are accessible to all threads that need to use them.

Concurrency

Previous
Async
SQL Syntax T-Shirts
No t-shirts available for this site.