条件变量类(condition_variable)是一个同步原语,它可以在同一时间阻塞一个线程或者多个线程,直到其他线程改变了共享变量(条件)并通知。
primitive 原语,表达的是基础、基本的,是其他复杂应用的构建基础。
二、为什么需要条件变量?- 减少轮询从而提高效率。没有条件变量,CPU会浪费时间反复轮询某一个条件。条件变量出现使得线程可以在不满足条件进行休眠,将资源让给有需要的其他线程;
- 线程之间的协调。两个线程之间执行可以变得有序,也就是一个线程执行完成后,另外一个线程才会执行;
- 复杂同步条件。有时候一个线程不仅需要知道资源可达,还需要知道一些额外信息,比如说生产消费者中,缓冲队列是否满之类的操作;
线程进入阻塞可以是sleep,也可以是wait。sleep期间所持有的锁不会释放,到时见会自动唤醒,而wait期间将会释放锁,唤醒还需要额外的条件。前者更多的用在模拟操作延迟,后者用于多线程协作场景。
试想一个场景,两个线程th1和th2,他们分别执行这两个不同的变量,th1的继续执行必须等到th2完成其计算过程才可以继续执行,那么将会有两种策略:
- 第一种,轮询th2是否执行标志位flag,th1种不断轮询标志位是否为true;
- 第二种,th1和th2通过条件变量进行联系,th1根据th2是否通知决定其是等待还是继续执行;
第一种方法,最简单的实现方法就是:
void th1_fun()
{
while(!flag)
{
std::this_thread::sleep_for(10ms);
}
//continue execute th1
}
检测到flag为false,线程进入休眠;检测到flag为true,退出while阻塞,继续执行,这个线程休眠是为了让其他线程有机会执行,也就是有机会让flag变成true,休眠时间如果过长,会导致响应延迟,如果休眠时间过短,cpu时间将会大部分浪费在判断flag是否改变。
第二种方法就是这里提到的条件变量,条件变量和轮询不一样的地方在于,他是用等待替代休眠的,这也就是说cpu不需要重复判断条件变量是否成立,而是通过另一个线程主动通知的方式告知无需继续等待。
三、std::condition_variable头文件#include
- 一个线程完成对数据的修改,另一个线程进行等待
- 数据修改完成,通知另一个线程已经完成修改
- 等待的线程收到通知,继续进行线程的执行
我们把对数据进行修改的线程称为通知线程,等待通知的线程称为等待线程。
3.2 通知端的具体工作- 获取一个
std::mutex
防止变量写冲突(通常是std::lock_guard
); - 对变量值进行修改;
- 对条件变量调用
notify_one
或者notify_all
通知(通知的时候不一定要处于锁定);
- 获得一个
std::unique_lock
,这个互斥锁与通知端的相同; - 条件变量执行
wait
wait_for
或wait_until
,等待操作将原子地完成释放互斥锁和挂起线程操作; - 当条件变量被通知时,超时或者虚假唤醒,线程将会被唤醒,互斥锁再次被获取,线程需要检查条件和假如时虚假唤醒则继续等待。
!!std::condition_variable
只可与 std::unique_lock
一同使用;此限制能让这种机制在一些平台取得最高的效率。当然如果你想使用与锁类型无关的条件变量,可以试试他的兄弟::std::condition_variable_any
。注意等待端释放和挂起是原子操作,具体原因点这里。
构造函数只有无参默认构造函数,无拷贝、无赋值。剩下的就是两类成员函数,一是通知方法,二是等待方法。
-
通知方法:要么通知所有人
notify_one
,要么通知一个人notify_all
。 -
等待方法:等待wait、等待一段时间wait_for和等待某个时刻wait_until。使用的方式就是“条件变量调用某种方法等待unique_lcok”
cond.wait(ulo);
调用wait方法导致当前线程阻塞直至条件变量被通知,或虚假唤醒发生,可选地循环直至满足某谓词。为了避免虚假唤醒,你可以使用谓词:
template
void wait( std::unique_lock& lock, Predicate pred );
等价于以下语句:
while (!pred()) {//不满足继续等待
wait(lock);
}
这个谓词应该理解为解除阻塞条件。
四、条件变量实例这个例子实现了按序打印并发线程:
class ConditionVarTest
{
public:
void printOne()
{
for(int i=0;i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?