man ページを引用すると:
条件変数を使用する場合、スレッドが続行する必要がある場合に真となる、各条件待機に関連付けられた共有変数を含むブール述語が常に存在します。pthread_cond_timedwait() または pthread_cond_wait() 関数からの誤ったウェイクアップが発生する可能性があります。pthread_cond_timedwait() または pthread_cond_wait() からの戻りは、この述語の値について何も意味しないため、そのような戻り時に述語を再評価する必要があります。
つまり、pthread_cond_wait
シグナルを送らなくても戻ることができます。少なくとも一見すると、これはかなりひどいように思えます。関数がランダムに間違った値を返したり、適切な return ステートメントに到達する前にランダムに戻ったりするようなものです。大きなバグのように思えます。しかし、これを修正するのではなく、man ページで文書化することを選択したという事実は、pthread_cond_wait
誤って起動してしまう正当な理由があることを示しているようです。おそらく、それがどのように機能するかについて本質的な何かがあり、それがそれを避けられないものにしているのでしょう。問題はそれが何であるかです。
なぜ誤って復帰するのでしょうかpthread_cond_wait
? 適切に信号が送られた場合にのみ起動することを保証できないのはなぜでしょうか? 誤った動作の理由を説明できる人はいますか?
ベストアンサー1
「偽のウェイクアップ」が意味する可能性のあることは少なくとも 2 つあります。
- ブロックされたスレッドは、条件への呼び出しや条件での呼び出しが発生しなかった
pthread_cond_wait
としても、呼び出しから戻ることができます。pthread_cond_signal
pthread_cond_broadcast
- または
pthread_cond_wait
の呼び出しが原因で でブロックされたスレッドが戻りますが、ミューテックスを再取得した後、基礎となる述語がもはや真ではないことが判明しました。pthread_cond_signal
pthread_cond_broadcast
しかし、後者のケースは、条件変数の実装が前者のケースを許可しない場合でも発生する可能性があります。プロデューサー/コンシューマー キューと 3 つのスレッドについて考えてみましょう。
- スレッド 1 は要素をデキューしてミューテックスを解放したばかりで、キューは空です。スレッドは、取得した要素を何らかの CPU で処理しています。
- スレッド 2 は要素をデキューしようとしますが、ミューテックスでチェックしたときにキューが空であることが判明し、 を呼び出し
pthread_cond_wait
、呼び出し内でブロックされてシグナル/ブロードキャストを待機します。 - スレッド 3 はミューテックスを取得し、キューに新しい要素を挿入し、条件変数に通知して、ロックを解除します。
- スレッド 3 からの通知に応じて、条件を待機していたスレッド 2 の実行がスケジュールされます。
- しかし、スレッド 2 が CPU にアクセスしてキュー ロックを取得する前に、スレッド 1 は現在のタスクを完了し、次の作業のためにキューに戻ります。スレッド 1 はキュー ロックを取得し、述語をチェックして、キューに作業があることを確認します。スレッド 3 が挿入した項目をキューから外し、ロックを解除して、スレッド 3 がキューに入れた項目に対して必要な処理を実行します。
- スレッド 2 は CPU にアクセスしてロックを取得しますが、述語をチェックすると、キューが空であることがわかります。スレッド 1 がアイテムを「盗んだ」ため、ウェイクアップは偽物であるように見えます。スレッド 2 は再び条件を待機する必要があります。
したがって、ループの下で述語を常にチェックする必要があるため、基礎となる条件変数に他の種類の誤ったウェイクアップがあっても違いはありません。