3

2 つの条件変数があります。

CondVar1
CondVar2

次のような 2 つのスレッドで使用されます (疑似コード):

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

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

これはデッドロックを引き起こす可能性がありますか? つまり、スレッド1が待機し、スレッド2がシグナルを送信し、スレッド2がWait()に入る前にスレッド1がシグナルを送信できます。つまり、スレッド2は決して戻りませんか?

ありがとう

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

ここでデッドロックにつながる可能性のある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 に答える