C++11 并发-锁与条件变量

互斥元

std::mutex

std::lock_guard

实现互斥元的 RAII 惯用语法,它在构造时锁定所给的互斥元,在析构时将互斥元解锁,从而保证被锁定的互斥元始终被正确解锁

std::unique_lock

提供了lock()、try_lock()和unlock()三个成员函数,它们会调用底层互斥元上同名的成员函数去做实际的工作,并且只是更新在std::unique_lock实例内部的一个标识,来表示该实例当前实例是否拥有此互斥元(如果标识表示了该实例拥有互斥元,则析构函数必须调用unlock();如果不拥有互斥元,则一定不能调用unlock())。因此std::unique_lock对象的大小通常大于std::lock_guard对象;使用std::unique_lock时,由于需要对标识进行相应的更新或判断在性能上会有些许损失

其灵活性还体现在可以在作用域之间转移锁的所有权

std::lock

待补充

加解锁的一些未定义行为

待补充

共享互斥元

boost::shared_mutex

boost::unique_lock<boost::shared_mutex>

写锁

boost::shared_lock<boost::shared_mutex>

读锁

递归互斥元

std::recursive_mutex

待补充

条件变量

从概念上说,条件变量与某些事件或其他条件相关,并且一个或多个线程可以等待该条件被满足。当某个线程已经确定条件得到满足,它就可以通知一个或多个正在条件变量上进行等待的线程,以便唤醒它们并让它们继续处理

std::condition_variable

等待操作

调用wait()函数需要传入锁对象,以及表示正在等待的条件的判断函数(判断函数可以使用lambda表达式)

调用wait()函数时,其内部首先会调用所提供的判断函数:

  • 如果满足条件(lambda返回true)则返回,当前线程继续执行
  • 如果不满足条件,则将当前线程置于等待状态(加入这个条件变量的等待队列)并解锁互斥元

当wait函数被唤醒时(其他线程调用通知或伪唤醒):

  • 重新获取互斥元(加锁)
  • 执行上面的一系列判断及相应操作

伪唤醒

当等待线程重新获取互斥元并检查条件时,如果它并非直接响应另一个线程的通知,即伪唤醒

丢失通知

在wait操作的实现流程的分析中,判断不满足条件与之后的所有处理并非是个原子操作,因此当前线程进入等待状态前,有可能其他线程的通知已经发出,这样就丢失了通知。具体实例可参考:线程池学习

std::condition_variable_any

灵活性更大,所以可能会有大小、性能或者操作系统资源方面的额外代价

原文地址:https://www.cnblogs.com/wangzhiyi/p/13659334.html