条件变量
这一章主要讲讲条件变量condition_variable。条件变量是一个非常神奇的存在,是线程间交互的一种方式。
C++11提供了condition_variable类。使用时需要include头文件<condition_variable>。
如果把变量区看成是一座房子,那么前面两章频繁用到的mutex可以看成是房门的锁,正常来说是房门常年打开的,锁并用不上。但是有了多线程以后,为了防止多个线程一窝蜂胡乱篡改里面的数据,所以就有了锁的概念。
现在假设每个线程都有一个管理锁的人,叫lock_guard,或者unique_lock,但是一次只能有一个人能够去操作锁(锁上或者是解锁)。一般来说他们是轮流去操作锁。而condition_variable则可以看做是门童,如果没有满足条件,门童就会通知线程的管锁人必须要休眠而不可以操作锁,可是一旦条件满足,他就会唤醒某些线程的管锁人可以去操作锁了。
#include#include #include #include #include using namespace std;bool ready = false;bool processed = false;mutex mu;condition_variable cv;string data;void worker_thread(){ unique_lock locker(mu); //ready = false,此处相当于全局变量区的门童通知t线程休眠 cv.wait(locker, [](){ return ready;}); //ready = true,休眠结束。此时locker上锁,开始修改变量 cout<<"start processing data"< locker(mu); //locker开始上锁,main线程修改全局变量 ready = true; cout<<"main signals data ready for processing"<
上面的代码中需要注意一下几点:
1. 代码中的 [](){return ready;}是匿名函数,也可以用循环的写法。
//cv.wait(locker, [](){return ready;}); //或者写成while(ready==false) cv.wait(locker);
注意是while(ready == false),不是if(ready == false),因为wait的唤醒可能由于系统的原因被唤醒,这个的时机是不确定的。这个过程也被称作伪唤醒(spurious wakeup)。
如果在错误的时候被唤醒,就开始执行了后面的操作就会造成错误。
2. 注意cv.wait() 和cv.notify_all()或者cv.notify_one()需要搭配使用才能真正发挥条件变量的作用。
3. cv.notify_one()指的是通知其中某一个线程,cv.notify_all()指的是通知全部线程。
参考:
https://www.jianshu.com/p/c1dfa1d40f53