C++11coreintermediate
std::condition_variable (C++11 Addition)
C++11 · Modern Revolution · Compiler flag: -std=c++11
Explanation
A synchronization primitive that allows threads to wait until a condition is met, enabling producer-consumer patterns and other thread coordination scenarios.
Real-World Scenario
Implement a thread-safe task queue where worker threads sleep until new tasks arrive.
Quick Snippet
snippet.cpp
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
// proceed with work
}Full Example
condition_variable.cpp
// CodeNebula - C++11 Example: std::condition_variable
// Compile: g++ -std=c++11 -Wall -Wextra -pthread -o example condition_variable.cpp
//
// This example demonstrates:
// - std::condition_variable for thread synchronization
// - wait() with predicate to avoid spurious wakeups
// - notify_one() and notify_all()
// - Producer-consumer pattern
// - Simple event signaling between threads
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <string>
#include <vector>
#include <chrono>
// ============================================================
// 1. Simple event signaling
// ============================================================
std::mutex eventMutex;
std::condition_variable eventCV;
bool eventReady = false;
void waitForEvent() {
std::unique_lock<std::mutex> lock(eventMutex);
std::cout << " Waiter: waiting for event..." << std::endl;
// wait() with predicate: only returns when predicate is true
eventCV.wait(lock, [] { return eventReady; });
std::cout << " Waiter: event received!" << std::endl;
}
void signalEvent() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard<std::mutex> lock(eventMutex);
eventReady = true;
std::cout << " Signaler: setting event" << std::endl;
}
eventCV.notify_one(); // Wake one waiting thread
}
// ============================================================
// 2. Producer-Consumer queue
// ============================================================
class MessageQueue {
std::queue<std::string> queue_;
std::mutex mutex_;
std::condition_variable cv_;
bool finished_ = false;
public:
void produce(const std::string& msg) {
{
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(msg);
std::cout << " Produced: " << msg << std::endl;
}
cv_.notify_one();
}
std::string consume() {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this] { return !queue_.empty() || finished_; });
if (queue_.empty()) return ""; // Finished, no more items
std::string msg = queue_.front();
queue_.pop();
return msg;
}
void setFinished() {
{
std::lock_guard<std::mutex> lock(mutex_);
finished_ = true;
}
cv_.notify_all(); // Wake ALL waiting consumers
}
};
// ============================================================
// 3. notify_all: barrier-like synchronization
// ============================================================
std::mutex barrierMutex;
std::condition_variable barrierCV;
bool startSignal = false;
void racerThread(int id) {
{
std::unique_lock<std::mutex> lock(barrierMutex);
barrierCV.wait(lock, [] { return startSignal; });
}
std::cout << " Racer " << id << " started!" << std::endl;
}
int main() {
std::cout << "=== std::condition_variable ===" << std::endl;
// Simple event
std::cout << "\n--- Simple event signaling ---" << std::endl;
std::thread waiter(waitForEvent);
std::thread signaler(signalEvent);
waiter.join();
signaler.join();
// Producer-Consumer
std::cout << "\n--- Producer-Consumer ---" << std::endl;
MessageQueue mq;
std::thread producer([&mq]() {
mq.produce("Message A");
mq.produce("Message B");
mq.produce("Message C");
mq.setFinished();
});
std::thread consumer([&mq]() {
while (true) {
std::string msg = mq.consume();
if (msg.empty()) break;
std::cout << " Consumed: " << msg << std::endl;
}
std::cout << " Consumer: done" << std::endl;
});
producer.join();
consumer.join();
// notify_all barrier
std::cout << "\n--- notify_all (start gate) ---" << std::endl;
std::vector<std::thread> racers;
for (int i = 0; i < 3; ++i) {
racers.emplace_back(racerThread, i);
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << " GO!" << std::endl;
{
std::lock_guard<std::mutex> lock(barrierMutex);
startSignal = true;
}
barrierCV.notify_all(); // Release all racers
for (auto& t : racers) t.join();
return 0;
}
// Expected output (thread ordering may vary):
// === std::condition_variable ===
//
// --- Simple event signaling ---
// Waiter: waiting for event...
// Signaler: setting event
// Waiter: event received!
//
// --- Producer-Consumer ---
// Produced: Message A
// Produced: Message B
// Produced: Message C
// Consumed: Message A
// Consumed: Message B
// Consumed: Message C
// Consumer: done
//
// --- notify_all (start gate) ---
// GO!
// Racer 0 started!
// Racer 1 started!
// Racer 2 started!
Run command
g++ -std=c++11 -Wall -Wextra -pthread -o example condition_variable.cpp