原文来自:http://chenlq.net/vc11-bit-sweet-condition-variable-condition_variable-header-files.html
天啊,cppblog的编辑器能不能再烂一点?
有兴趣的同学,去看原文吧,无语了 :(
条件变量,是C++11中为了简化线程之间访问某个共享资源而提出的。在这个应用场景中,这个共享资源往往表现为某种条件。例如在生产者-消费者模式中,我们往往需要判断用于存放产品的容器是在什么状态(条件)下。如果容器是空的,生产者线程可以继续,而消费者线程则需要暂停,而如果容器已经满了,生产者线程需要暂停,而消费者线程可以继续。而在这个场景中,我们就可以用条件变量来协调两个线程之间的动作。关于条件变量在生产者-消费者模式下的应用,我给出了一个例子。
条件变量在协调两个线程之间的协作的时候非常有用,我们这里再补充一个例子。假设我们需要为政府设计一个程序来管理路灯。在这里,我们用一个线程来检查是否到了观灯的时间,而另外一个线程则负责在条件满足后关闭路灯。
#include
#include // 时间工具
#include // 线程
#include // 条件变量
#include // 互斥
using namespace std;
using namespace std::chrono;
// 条件变量
condition_variable cond;
// 互斥
mutex m;
// 表示条件的共享资源
bool morning = false;
// 检查是否到了关灯的时间
void check()
{
// 记录开始时间
auto start = system_clock::now();
do
{
// 当前线程休眠1000毫秒
this_thread::sleep_for(milliseconds(1000));
cout<<"it is still night."<<endl;
} // 检查是否已经到了关灯的时刻
// 这里用seconds(4)表示路灯持续4秒
while ( system_clock::now() < start + seconds(4));
// 到达关灯时间,锁定互斥对象,
// 修改表示条件的共享数据morning
lock_guard lk(m);
cout<<"it is morning."<<endl;
morning = true;
// 用notify_one()通知另外的线程,条件已经发送变化
cond.notify_one();
}
/// 关灯线程
void turnoff()
{
// 锁定互斥对象,访问表示条件的共享资源morning
unique_lock lk(m);
// 构造一个循环,只要条件没有满足
// 就一直执行条件变量的wait()方法,让当前线程等待
while(!morning)
{
cond.wait(lk);
}
// 条件满足。执行关灯动作
cout<<"turn off the light."<<endl;
}
int main(int argc, char* argv[])
{
// 创建两个线程,分别执行检查和关灯的动作
thread c(check);
thread t(turnoff);
c.join();
t.join();
return 0;
}
从这个例子中,我们可以得到这样一些使用条件变量的要点:
条件变量总是需要与一个表示条件的共享资源以及对这个共享资源进行访问控制的互斥对象。这就是我们在程序的开始部分定义的morning,m和cond。
// 条件变量
condition_variable cond;
// 互斥
mutex m;
// 表示条件的共享资源
bool morning = false;
这三者几乎总是相伴同时出现。
在一个线程中,我们需要在条件满足的时候修改表示条件的共享资源的值,然后用条件变量的notify_one()或者notify_all()通知正在等待的线程。这就是
// 到达关灯时间,锁定互斥对象,
// 修改表示条件的共享数据morning
lock_guard lk(m);
cout<<"it is morning."<<endl;
morning = true;
// 用notify_one()通知另外的线程,条件已经发送变化
cond.notify_one();
而在另外一个线程中,我们需要构造一个以共享资源为条件的无限循环,当条件无法满足时,就用条件变量的wait()或者wait_until()等函数进行等待,直到条件得到满足,循环结束。
// 锁定互斥对象,访问表示条件的共享资源morning
unique_lock lk(m);
// 构造一个循环,只要条件没有满足
// 就一直执行条件变量的wait()方法,让当前线程等待
while(!morning)
{
cond.wait(lk);
}
总结起来,条件变量简化了对表示条件的共享资源的访问,也省去了对共享资源的频繁的锁操作,进一步提高了效率。