C++ std::condition_variable: A Powerful Tool for Synchronization

beginner
12 min

C++ std::condition_variable: A Powerful Tool for Synchronization

Welcome back to CodeYourCraft! Today, we're diving into one of the most powerful synchronization tools in C++ – the std::condition_variable. This versatile beast helps manage concurrent execution, signaling threads, and handling complex multi-threaded scenarios. Let's explore it together! šŸŽÆ

What is std::condition_variable?

std::condition_variable is a C++11 library that facilitates communication between threads. It allows one or more threads to wait for a particular condition to become true, and it notifies other threads when that condition is met. šŸ“

Why use std::condition_variable?

Imagine having a busy kitchen where multiple cooks are preparing different dishes simultaneously. One cook can't start preparing a certain dish until another finishes preparing its required ingredients. std::condition_variable helps these cooks (threads) communicate effectively and synchronize their work. šŸ’”

Key Concepts

  • Waiting: A thread can wait on a condition variable, indicating that it's willing to be blocked until a specific condition is met.
  • Notifying: When the condition is met, another thread can notify the waiting thread, allowing it to resume execution.
  • Locking: std::condition_variable relies on a std::unique_lock to protect shared data from race conditions.

A Simple Example šŸ’»

Let's create a simple producer-consumer problem using std::condition_variable. Here, a producer generates numbers, and a consumer consumes them.

cpp
#include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> std::queue<int> numbers; std::mutex mtx; std::condition_variable cvProducer, cvConsumer; void producer() { int count = 0; for (int i = 0; i < 10; ++i) { std::unique_lock<std::mutex> lock(mtx); cvProducer.wait(lock, []{ return numbers.size() < 5; }); // wait until queue size < 5 numbers.push(count); std::cout << "Produced: " << count++ << "\n"; lock.unlock(); cvConsumer.notify_one(); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } } void consumer() { while (true) { std::unique_lock<std::mutex> lock(mtx); cvConsumer.wait(lock, []{ return !numbers.empty(); }); // wait until queue is not empty int number = numbers.front(); numbers.pop(); std::cout << "Consumed: " << number << "\n"; lock.unlock(); cvProducer.notify_one(); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } } int main() { std::thread producerThread(producer); std::thread consumerThread(consumer); producerThread.join(); consumerThread.join(); return 0; }

Quiz šŸŽ²

Quick Quiz
Question 1 of 1

What is the purpose of the `std::unique_lock` in the example?

That's it for today! In the next lesson, we'll delve deeper into std::condition_variable and explore more advanced usage scenarios. Stay tuned and happy coding! šŸ’”šŸŽÆ