C++条件变量的坑

发布于 2021-09-19  61 次阅读


条件变量是与锁结合使用,用于控制线程同步的,其具有以下基本操作:

  • cond.wait(lock, condition),线程在这里判断condition,如果不满足,则解锁,进入休眠状态。
  • cond.notifyOne() 随机唤醒一个线程
  • cond.notifyAll() 唤醒所有线程

这里的坑就出在这个 notifyAll() 上。虽然这里唤醒了所有线程,但实际上也只有一个线程能获得锁并继续执行,这时就涉及到底层实现了。

当线程因为条件变量陷入等待时,会把他们加入条件变量的等待队列中。此时若有多个线程被唤醒,那么只有竞争到锁的线程才会继续执行。而关键在于其他没有获得锁的线程此时会发生等待转移 --> 从条件变量的等待队列转移到锁的等待队列。这个时候如果一开始那个竞争到锁的线程完成了操作,对条件进行了修改,并最终释放了锁,此时处于锁的等待队列中的线程就会继续竞争锁,并向下执行,但此时的条件已经由 一开始那个竞争到锁的线程进行了修改,条件并不满足,这种情况就容易出现不符合意图的操作。

我们把这种情况称为虚假唤醒。

解决这个问题的办法很简单:

while (condition) {
    cond.wait(lock, condition);
}

在最外头添加一个对条件判断的while循环即可,这样即使发生虚假唤醒,也会因为这个while循环检测到条件其实并不满足,从而重新被添加到条件变量的等待队列中。


当其他人都认为你要鸽的时候,你鸽了,亦是一种不鸽