条件变量死锁

时间:2013-04-09 20:54:46

标签: c++ multithreading synchronization

我的代码中与使用条件变量相关的死锁问题。这更像是一个设计问题,而不是纯粹的代码问题。一旦我理解了正确的设计,我就没有问题。我有以下情况:

  1. 线程A等待条件变量。
  2. 线程B调用notify_all,线程A唤醒。
  3. 这当然是我想要发生的事情,并且当一切按预期工作时会发生什么。但有时候,我会得到以下情况:

    1. 线程A在开始等待条件变量之前执行代码。
    2. 线程B调用notify_all,认为线程A正在等待。
    3. 线程A开始等待条件变量,没有意识到线程B已经告诉它停止等待。死锁。
    4. 解决此问题的最佳方法是什么?我想不出一个可靠的方法来检查线程A是否实际上正在等待,以便知道何时应该在线程B中调用notify_all。我是否必须求助于timed_lock?我讨厌。

2 个答案:

答案 0 :(得分:6)

在线程A等待条件变量之前的时间段内,它必须持有互斥锁。最简单的解决方案是确保线程B在调用notify_all时持有相同的互斥锁。所以像这样:

std::mutex m;
std::condition_variable cv;
int the_condition = 0;

Thread A: {
  std::unique_lock<std::mutex> lock(m);
  do something
  while (the_condition == 0) {
    cv.wait(lock);
  }
  now the_condition != 0 and thread A has the mutex
  do something else
} // releases the mutex;

Thread B: {
  std::unique_lock<std::mutex> lock(m);
  do something that makes the_condition != 0
  cv.notify_all();
} // releases the mutex

这保证了线程B只在线程A获取互斥锁之前或线程A在条件变量上等待时才执行notify_all()。

这里的另一个关键是while循环等待the_condition变为true。一旦A具有互斥锁,任何其他线程都不可能更改the_condition直到A测试了the_condition,发现它为false并开始等待(从而释放互斥锁)。

关键是:你真正在等待的是the_condition的值变为非零,std :: condition_variable :: notify_all只是告诉你线程B认为线程A应该被唤醒并重新测试。 / p>

答案 1 :(得分:2)

条件变量必须始终与互斥锁相关联,以避免由一个准备等待的线程创建的竞争条件和另一个可能在第一个线程实际等待它之前发出信号的线程导致死锁。线程将永远等待从未发送的信号。可以使用任何互斥锁,互斥锁和条件变量之间没有明确的链接。