2012-09-09 156 views
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信号,然后可以在thread2进入Wait()之前thread1信号,这意味着thread2永远不会返回?

感谢

+0

反过来也是可能的:如果线程2个运行线程1之前,在上'ConVar1信号'在线程1调用'Wait'之前可能会丢失。 – Tudor

回答

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

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 
} 

需要注意以下几点:大多数图书馆允许在条件变量假尾流。尽管可以实施避免虚假唤醒的条件变量,但操作成本会更高,因此在继续之前要求用户重新检查状态(参见[1]中的while循环))被认为是更坏的恶习。

某些库,特别是C++ 11,允许传递一个谓语和将在内部实现循环:cond.wait(lock, [&queue](){ return !queue.full(); });