3

我有两个条件变量:

CondVar1
CondVar2

在这样的两个线程中使用(伪代码):

// thread1 starts in 'waiting' mode, and then Thread2 signals
void Thread1()
{
    CondVar1->Wait();
    CondVar2->Signal();
}

void Thread2()
{
    CondVar1->Signal();
    CondVar2->Wait();
}

这会导致死锁吗?意思是,thread1 等待,thread2 发出信号,然后thread1 可以在thread2 进入Wait() 之前发出信号,意思是thread2 永远不会返回?

谢谢

4

2 回答 2

4

您通常不只是等待条件变量。常用模式是持有一个锁,检查一个变量,该变量决定你是否可以继续,以及你是否不能在条件下等待:

// pseudocode
void push( T data ) {
   Guard<Mutex> lock( m_mutex );   // Hold a lock on the queue
   while (m_queue.full())     // [1]
      m_cond1.wait(lock);         // Wait until a consumer leaves a slot for me to write
   // insert data
   m_cond2.signal_one();      // Signal consumers that might be waiting on an empty queue
}

需要注意的一些事情:大多数库都允许条件变量中的虚假唤醒。虽然可以实现避免虚假唤醒的条件变量,但操作的成本会更高,因此要求用户在继续之前重新检查状态被认为是一种较小的邪恶(while循环 [1])。

一些库,尤其是 C++11,允许您传递谓词,并将在内部实现循环:cond.wait(lock, [&queue](){ return !queue.full(); } );

于 2012-09-09T14:25:32.637 回答
2

这里有两种情况可能导致死锁:

  1. 在正常执行中,您描述的那个。有可能在线程到达对 的调用之前向变量发出信号Wait,因此信号丢失。
  2. 可能会发生虚假唤醒,导致第一个线程Wait在实际发出信号之前离开调用,从而发出尚未等待的线程 2 的信号。

使用信号机制时,您应该按如下方式设计代码:

bool thread1Waits = true;
bool thread2Waits = true;

void Thread1()
{
    while(thread1Waits) CondVar1->Wait();
    thread2Waits = false; 
    CondVar2->Signal();
}

void Thread2()
{
    thread1Waits = false;
    CondVar1->Signal();
    while(thread2Waits) CondVar2->Wait();
}

当然,这假设有锁保护条件变量,并且线程 1 在线程 2 之前运行。

于 2012-09-09T14:23:29.893 回答