8

条件変数の使用に関連するコードのデッドロックに問題があります。これは、純粋なコードの問題というよりも、設計上の問題です。正しい設計を理解すれば、実際にコードを書くことに問題はありません。次のシナリオがあります。

  1. スレッド A は条件変数を待機します。
  2. スレッド B が notify_all を呼び出し、スレッド A が起動します。

もちろん、これは私が望んでいることであり、すべてが期待どおりに機能するときに起こることです。ただし、代わりに次のシナリオが表示される場合があります。

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

これを解決する最善の方法は何ですか? スレッド B でいつ notify_all を呼び出す必要があるかを知るために、スレッド A が実際に待機しているかどうかを確認する信頼できる方法が思いつきません。timed_lock に頼る必要がありますか? 私は嫌いです。

4

2 に答える 2

9

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

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() を実行することが保証されます。

ただし、ここでもう 1 つの重要な点は、while ループが the_condition が true になるのを待機していることです。A がミューテックスを取得すると、A が the_condition をテストし、それが false であることを検出し、待機を開始する (したがってミューテックスを解放する) まで、他のスレッドが the_condition を変更することはできません。

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

于 2013-04-09T21:05:41.043 に答える