C++ Standard Library<condition_variable>
In multithreaded programming, synchronization between threads is a very important issue.
The C++11 standard introduced<condition_variable>The header file provides a mechanism that allows threads to suspend when certain conditions are not met, until other threads notify them that the conditions have been satisfied.
condition_variableIt is an advanced tool for synchronization between threads, which is safer and more convenient than using low-level synchronization primitives (such as mutexes and condition variables).
condition_variableIt is a class template used to implement synchronization between threads in a multithreaded environment. It allows one or more threads to wait for a certain condition to become true, while other threads can wake up these waiting threads.
Syntax
The following arecondition_variablebasic syntax:
#include <condition_variable>
void notify_one() {
// 唤醒一个等待的线程
}
void notify_all() {
// 唤醒所有等待的线程
}
template <class Mutex>
class condition_variable {
public:
condition_variable();
~condition_variable();
void wait(unique_lock<mutex>& lock);
void wait_for(unique_lock<mutex>& lock, chrono::duration<Rep, Period> const& rel_time);
void wait_until(unique_lock<mutex>& lock, chrono::time_point<Clock, Duration> const& abs_time);
void notify_one() noexcept;
void notify_all() noexcept;
};
Example
Below is an example usingcondition_variableA simple example of it, demonstrating the basic implementation of the producer-consumer problem.
Example
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> product;
void producer(int id) {
for (int i = 0; i < 5; ++i) {
std::unique_lock<std::mutex> lck(mtx);
product.push(id * 100 + i);
std::cout << "Producer " << id << " produced " << product.back() << std::endl;
cv.notify_one();
lck.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumer(int id) {
while (true) {
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []{ return !product.empty(); });
if (!product.empty()) {
int prod = product.front();
product.pop();
std::cout << "Consumer " << id << " consumed " << prod << std::endl;
}
lck.unlock();
}
}
int main() {
std::thread producers[2];
std::thread consumers[2];
for (int i = 0; i < 2; ++i) {
producers[i] = std::thread(producer, i + 1);
}
for (int i = 0; i < 2; ++i) {
consumers[i] = std::thread(consumer, i + 1);
}
for (int i = 0; i < 2; ++i) {
producers[i].join();
consumers[i].join();
}
return 0;
}
The output of this program may vary because it depends on thread scheduling. However, you will see the producer produce items, and then the consumer consume them. The output will be similar to:
Producer 1 produced 100 Producer 2 produced 200 Consumer 1 consumed 100 Producer 1 produced 101 Consumer 2 consumed 200 Producer 2 produced 201 Consumer 1 consumed 101 ...
Notes
- Usage
condition_variableWhen doing so, you must ensure that the mutex is acquired before waiting, and released after being woken up. wait、wait_forandwait_untilThe functions release the mutex, and then reacquire it during the wait.notify_onewakes up one waiting thread, whilenotify_allwakes up all waiting threads.