2013-04-09 22 views
6

条件変数の使用に関連するコードのデッドロックに問題があります。これは純粋なコードの質問よりも設計上の問題のほうが多いです。正しいデザインを理解すれば、実際にコードを書くのに問題はありません。私は以下のシナリオを持っています:条件変数デッドロック

  1. スレッドAは条件変数を待ちます。
  2. スレッドBはnotify_allを呼び出し、スレッドAはウェイクアップします。

これはもちろん私が起こりたいことであり、すべてが期待どおりに動作するときに起こります。しかし時々、私は次のシナリオを代わりに得ます:

  1. スレッドAは、条件変数の待機を開始する直前にコードを実行します。
  2. スレッドBはスレッドAが待機していると考えてnotify_allを呼び出します。
  3. スレッドAは、スレッドBが待機を停止するように指示したことを認識せずに、条件変数の待機を開始します。デッドロック。

これを解決する最善の方法は何ですか?スレッドAで実際に待機しているかどうかを確認する信頼できる方法は考えられません。なぜ私はスレッドBでnotify_allを呼び出すべきかを知るためにtimed_lockに頼らざるを得ませんか?私は嫌いだ。

+0

あなたはどのライブラリを使用していますか?どのようなOSですか? –

+0

セマフォを使用します。 –

答えて

5

スレッドAが条件変数を待つ直前の期間、mutexを保持している必要があります。最も簡単な解決策は、スレッドBがnotify_allを呼び出すときに同じmutexを保持していることを確認することです。したがって、このような何か:

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 

これは、スレッドAが条件変数を待っている間に、スレッドAがミューテックスを取得したりする前に、スレッドBのみnotify_all()のいずれかを行うことを保証します。

ここでもう一方のキーは、the_conditionがtrueになるのを待っているwhileループです。 Aがmutexを持つと、他のスレッドはAがthe_conditionをテストし、falseを見つけて待機し(したがってmutexを解放する)、the_conditionを変更することはできません。

ポイントは:あなたが本当に待っているのは、the_conditionの値がゼロでないことです。std :: condition_variable :: notify_allはスレッドBがスレッドAが起床して再テストする必要があると考えることを伝えています。

+3

+1 'std :: condition_variable :: wait'にも述語を受け入れるオーバーロードがあることに注意してください。代わりに 'while(the_condition == 0)cv.wait(lock);'の代わりに 'cv.wait(lock、[&] {return the_condition!= 0;})を書くことができます; –

+0

@AndrewDurward:それは甘いです!私はそれを知らなかった。 –

+1

ああ、もちろん。間違いなく簡単。実際にスレッドBで真になるように条件を変更するときは、条件変数が使用するのと同じmutexをロックしてください。私はあなたの提案を自分のコードに実装し、問題を解決します。ありがとうございました! –

2

条件変数は、待機する準備をしているスレッドによって作成された競合状態と、最初のスレッドが実際に待機してデッドロックが発生する前に条件を通知するスレッドを避けるために常にmutexと関連付ける必要があります。スレッドは、決して送信されない信号を待っています。すべてのミューテックスを使用できますが、ミューテックスと条件変数の間に明示的なリンクはありません。