两个条件变量并避免死锁

时间:2012-09-09 14:16:17

标签: c++ multithreading thread-safety

我有两个条件变量:

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永远不会返回?

由于

2 个答案:

答案 0 :(得分: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}}循环[1]之前要求用户重新检查状态被认为是较小的罪恶。 )。

某些库,特别是C ++ 11,允许您传递谓词,并在内部实现循环:while

答案 1 :(得分:2)

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

  1. 在正常执行中,您描述的那个。在线程到达Wait的调用之前,可能会发出变量信号,因此信号会丢失。
  2. 可能会发生虚假唤醒,导致第一个线程在实际发出信号之前将呼叫留给Wait,从而发出尚未等待的线程2的信号。
  3. 使用信令机制时,您应该按如下方式设计代码:

    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之前运行。