1. std::condition_variable
C++标准库提供了条件变量的两种实现:
std::condition_variable
、std::condition_variable_any
。
它们都在标准库的头文件<condition_variable>
内声明。
两者都需配合互斥,方能提供妥当的同步操作。
std::condition_variable仅限于与std::mutex一起使用;
由于std::condition_variable_any更加通用,它可能产生额外开销,涉及其性能、自身的体积或系统资源等,因此std::condition_variable应予优先采用,除非有必要令程序更灵活。
2. 代码
#include <mutex>
#include <condition_variable>
#include <thread>
#include <queue>
#include <iostream>
std::mutex mut;
std::queue<int> data_queue;
std::condition_variable data_cond;
void process(int data)
{
std::cout << "process, print data: " << data << std::endl;
}
void data_preparation_thread()
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(12345);
data_cond.notify_one();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
std::cout << "data_preparation_thread add data to data_queue" << std::endl;
}
}
void data_processing_thread()
{
while (true)
{
std::unique_lock<std::mutex> lk(mut);
//data_cond.wait(lk, [] {return !data_queue.empty(); });
data_cond.wait(lk, [] {
if (data_queue.empty())
{
std::cout << "data_queue is empty, wait" << std::endl;
return false;
}
std::cout << "data_queue is not empty, process data" << std::endl;
return true;
});
int data = data_queue.front();
data_queue.pop();
lk.unlock();
process(data);
}
}
int main()
{
std::thread t1(data_preparation_thread);
std::thread t2(data_processing_thread);
t1.join();
t2.join();
}
运行效果:
代码解析:
注意:
wait()
在内部调用传入的lambda函数,判断条件是否成立:若成立(lambda函数返回true),则wait()返回,进入下一步;否则(lambda函数返回false),wait()解锁互斥,并令线程进入阻塞状态或等待状态;notify_one()
发送通知后,需要unlock
后,wait()
才能收到通知;- data_processing_thread线程中使用的是
std::unique_lock
而不是std::lock_guard
,原因是这样的:线程data_processing_thread在wait()等待期间,必须解锁互斥,而结束等待之后,必须重新加锁,但std::lock_guard无法提供这种灵活性; - 如果有多个线程在wait(),
notify_one()
随机唤醒一个,而notify_all()
会唤醒所有wait()的线程