C++11下条件变量之虚假唤醒

概述:

条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制。典型的场景包括生产者-消费者模型,线程池实现等。 

对条件变量的使用包括两个动作:

在线程开发的过程中,肯定会遇到线程同步,我们会选择C++11中的condition_varible来方便我们处理。当在项目中看到前辈这样写

std::unique_lock<std::mutex> lock(m_mutex);

while(!m_isReady)  //防止虚假唤醒

{

m_condition.wait(lock);

......

}

时,特别是注释 突然感觉自己有必要去了解一下这个名词,于是记录下自己的理解。

条件变量是依赖其他共享变量事项工作的,一般情况下搭配互斥锁变量mutex一起使用。

函数说明:

条件变量的wait/wait_for/wait_until:1.调用时使当前线程保持休眠状态,同时修改lock为解锁状态(这两部分操作是原子操作),wait_for/wait_until要求传入一个附加条件 在信号量长时间没有被唤醒时 停止等待。

2.在调用notify_one/notify_all后,条件变量被唤醒后,重新竞争互斥锁,并对互斥锁lock后才返回wait调用

虚假唤醒:

处于等待的添加变量可以通过notify_one/notify_all进行唤醒,调用函数进行信号的唤醒时,处于等待的条件变量会重新进行互斥锁的竞争。没有得到互斥锁的线程就会发生等待转移(wait morphing),从等待信号量的队列中转移到等待互斥锁的队列中,一旦获取到互斥锁的所有权就会接着向下执行,但是此时其他线程已经执行并重置了执行条件,这是该线程执行就可并引发未定义的错误。

结论:

所以我们在实际的代码中用while而不使用if,while可以有效的避免虚假唤醒引起的问题。其实,在条件变量中是可以实现杜绝虚假唤醒的,但是这样做会很大程度上影响条件变量的效率,因此将这个问题抛给了程序员。

另:

在进行条件变量的唤醒时我们通常有两种做法 1.互斥锁unlock。notify条件变量。2.notify条件变量,互斥锁unlock。这两种方式下。第一种情况等待的条件变量在被唤醒时可以立刻获取互斥锁的所有权进行代码执行。而在第二种情况下,被唤醒的条件变量,要重新放到互斥锁的竞争队列中,等待互斥锁unlock,这样就就行了两次的上下文的切换,影响执行效率

注:以上是个人理解,如有不正确的地方,欢迎指正


展开阅读全文

没有更多推荐了,返回首页