文章目录
前言
在C++11中,对于多线程的同步问题,我们可以使用条件变量condition_variable
;当条件不满足时,相关线程被一直阻塞,直到某种条件出现,该线程才会被唤醒。condition_variable
类的成员函数如下:
一、条件变量condition_variable
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括:
- 一个线程因等待“条件变量的条件成立”而挂起;
- 其他线程使“条件成立”,给出信号,从而唤醒被等待的线程。
1、应用场景
当需要死循环判断某个条件成立与否时【true or false】,如果多开一个线程死循环来判断,这样非常消耗CPU。使用条件变量,可以让当前线程wait,释放CPU,如果条件改变时,我们再notify退出线程,再次进行判断,这样就省去了CPU轮询空耗资源。
2、具体动作
即使共享变量是原子性的,它也必须在mutex的保护下被修改,这是为了能够将改动正确发布到正在等待的线程。
任意要等待std::condition_variable的线程必须:
- 获取
std::unique_lock<std::mutex>
,这个mutex正是用来保护共享变量(即“条件”)的 - 执行
wait
,wait_for
或者wait_until
. 这些等待动作原子性地释放mutex,并使得线程的执行暂停 - 当获得条件变量的通知,或者超时,或者一个虚假的唤醒,那么线程就会被唤醒,并且获得mutex. 然后线程应该检查条件是否成立,如果是虚假唤醒,就继续等待。
【注: 所谓虚假唤醒,就是因为某种未知的罕见的原因,线程被从等待状态唤醒了,但其实共享变量(即条件)并未变为true。因此此时应继续等待】
二、具体函数说明
1、wait
1、wait(unique_lock <mutex>&lck)
当前线程的执行会被阻塞,直到收到 notify 为止。
2、wait(unique_lock <mutex>&lck,Predicate pred)
重载版本
当前线程仅在pred=false时阻塞;如果pred=true时,不阻塞
wait() 可依次拆分为三个操作:释放互斥锁、等待在条件变量上,暂停线程、再次获取互斥锁
2、notify_one:
notify_one():没有参数、没有返回值。
解除阻塞当前正在等待此条件的线程之一。如果没有线程在等待,则还函数不执行任何操作。如果超过一个,则选择任意一个等待线程唤醒。
3、wait_for
cv_status wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time)
bool wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time, Predicate pred)
重载版本
与 wait() 类似,不过 wait_for 可以指定一个时间段,在当前线程收到通知或者指定的时间 rel_time 超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_for 返回,剩下的处理步骤和 wait() 类似。
4、wait_until
与 wait_for 类似,但是 wait_until 可以指定一个时间点,在当前线程收到通知或者指定的时间点 abs_time 之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_until 返回,剩下的处理步骤和 wait_until() 类似
三、消费者和生产者模型
std::deque<int> q;
std::mutex mu;
std::condition_variable cond;
void function_1() //生产者
{
in