C++11并发学习
mutex
注意一点,mutex不能在本线程已经拥有锁的情况下执行lock函数,会报错,但是如果锁被其他线程拥有时执行lock不会有问题,只会阻塞当前线程而已。
unique_lock和lock_guard的区别
lock_guard只在构造的时候加锁,在析构的时候解锁,而unique_lock可以任意的解锁和锁定,同时在初始化的时候,unique_lock比lock_guard有更多的加锁策略,详情见这里,而且unique_lock比lock_guard有更多的成员函数,详情见这里。
关于条件变量
条件变量经常与互斥量mutex一起使用,C++11中没有提供信号量,我们可以用条件变量和mutex配合来达到信号量的作用,一开始看信号量的时候自己还有点和互斥量mutex没法区分用途上的区别,后来才渐渐明白一点就是互斥量和信号量的区别实际上互斥和同步之间的区别,可以认为同步是在互斥的基础上更进一步的,互斥只是强调两个线程之间之间存在无法同时执行的逻辑段,而同步则确定了两个线程不仅是无法同时执行,同时更加强调了两者之间的先后关系。
条件变量是如何和mutex一起使用的?
找到了《C++并发编程实战》的代码:
std::mutex mut; std::queue<data_chunk> data_queue; // 1 std::condition_variable data_cond; void data_preparation_thread() { while(more_data_to_prepare()) { data_chunk const data=prepare_data(); std::lock_guard<std::mutex> lk(mut); data_queue.push(data); // 2 data_cond.notify_one(); // 3 } } void data_processing_thread() { while(true) { std::unique_lock<std::mutex> lk(mut); // 4 data_cond.wait( lk,[]{return !data_queue.empty();}); // 5 data_chunk data=data_queue.front(); data_queue.pop(); lk.unlock(); // 6 process(data); if(is_last_chunk(data)) break; } }
notify会通知wait函数,这里的wait函数有两个变量,第一个是mutex,另一个是一个谓词,这里是lambda表达式,实际上在condition_virable内部有两个wait,在VS中自己看源码可以看到两个:
void wait(unique_lock<mutex>& _Lck) { // wait for signal // Nothing to do to comply with LWG 2135 because std::mutex lock/unlock are nothrow _Cnd_waitX(_Mycnd(), _Lck.mutex()->_Mymtx()); } template<class _Predicate> void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { // wait for signal and test predicate while (!_Pred()) wait(_Lck); }
可以看到我们这里使用的下面这个wait,我们将上面的wait称为waitA,下面的这个称为waitB。那么waitA执行的过程就是释放mutex并且进入等待直到被唤醒,那么为什么B又在A上面包了一层呢?我们使用条件变量的需求就是需要wait的线程能够及时唤醒,如果谓词里面的条件不满足肯定是不行的,而如果不包这一层,条件满足的保证就只剩下notify那边的线程了,健壮性不够。况且不仅如此,实际上还存在虚假唤醒的情况,因此需要检查谓词的结果,另外waitA的被唤醒要保证waitA函数的执行在notify函数执行之前,因此如果waitA的执行滞后了,也可以通过判断谓词是否符合要求如果符合要求直接进行下一步,也不需要经过wait的等待和唤醒。综上所述,这一层包装还是非常有效的。
另外,我们可以看到条件变量中使用的unique_lock而不是lock_guard,实际上unique_lock比lock_guard要灵活一些,
wait的执行逻辑
这里写的很不错,可以参考一下,可以很清楚地明白wait里面为什么要用unique_lock而不能用lock_guard https://stackoverflow.com/questions/6731027/boostunique-lock-vs-boostlock-guard
如何理解future
从这里看一下
C++11实现生产者消费者模式:https://blog.csdn.net/u013390476/article/details/52067321