一、condition_variable 类介绍
当 std::condition_variable 对象的某个 wait 类函数被调用的时候,它使用std::unique_lock(通过 std::mutex)来锁住当前的线程,当前的线程会一直被阻塞(进入睡眠等待状态),直到有其他的线程在同一个 std::condition_variable 对象上调用 notify 类函数来唤醒它。
std::condition_variable 对象通常使用 std::unique_lock</std::mutex>来等待,如果需要使用另外的 lockable 类型,可以使用 std::condition_variable_any 类
1、1 wait 操作
std::condition_variable 提供了两种 wait() 函数。
(1)无条件wait()
void wait (unique_lock<mutex>& lck);
当前线程调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。
(2)有条件wait()
template <class Predicate>
void wait (unique_lock<mutex>& lck, Predicate pred);
第二种情况设置了 Predicate,只有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。因此第二种情况类似以下代码:
while (!pred())
{
wait(lck);
}
1、2 notify操作
(1)notify_one()
std::condition_variable::notify_one()
唤醒某个等待(wait)线程。如果当前没有等待线程,则该函数什么也不做,如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
(2)notify_all()
std::condition_variable::notify_all()
唤醒所有的等待(wait)线程。如果当前没有等待线程,则该函数什么也不做。
示例:
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;//全局标志位
void printId(int i)
{
std::unique_lock<std::mutex> lck(mtx);
//如果标志位不为true,则等待
while (!ready)
{
//线程被阻塞,直到标志位变为true
cv.wait(lck);
}
cout << "thread: " << this_thread::get_id() << " id: " << i << endl;
}
void go()
{
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(printId, i);
}
cout << "create done." << endl;
go();
for (auto &t : threads)
{
t.join();
}
cout << "process done." << endl;
system("pause");
return 0;
}
二、生产者消费者模型
一般来说,生产者消费者模型可以通过 queue, mutex 和 condition_variable 来实现。下面是一个简单实现:
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<chrono>//定时
//定义了C++11标准中的一些表示线程、并发控制时原子操作的类与方法等.
#include<atomic>
using namespace std;
int main()
{
queue<int> production;
mutex mtx;
condition_variable cv;
bool ready = false;//是否有产品可以消费
bool done = false;//生产结束
std::thread producer(
[&]()->void {
for (int i = 1; i < 10; ++i)
{
//模拟实际生产过程
//睡眠持续时间/毫秒。表示当前线程休眠一段时间,
//休眠期间不与其他线程竞争CPU,根据线程需求,等待若干时间
this_thread::sleep_for(chrono::milliseconds(10));
cout << "producing " << i << endl;
unique_lock<mutex> lock(mtx);
production.push(i);
//有产品可以消费了
ready = true;
cv.notify_one();
}
//生产结束
done = true;
}
);
std::thread consumer(
[&]()->void {
unique_lock<mutex> lock(mtx);
while (!done || !production.empty())
{
//防止误唤醒
while (!ready)
{
cv.wait(lock);
}
while (!production.empty())
{
cout << "consuming " << production.front() << endl;
production.pop();
}
ready = false;
}
}
);
producer.join();
consumer.join();
system("pause");
return 0;
}
因为上了锁,所以两个线程交替执行。
本文参考:C++11 并发编程系列(三):条件变量