web-dev-qa-db-ja.com

なぜpthread_cond_waitに誤ったウェイクアップがあるのですか?

マニュアルページを引用するには:

条件変数を使用する場合、スレッドが続行する必要がある場合はtrueである各条件待機に関連付けられた共有変数を含むブール述語が常にあります。 pthread_cond_timedwait()またはpthread_cond_wait()関数からの誤ったウェイクアップが発生する場合があります。 pthread_cond_timedwait()またはpthread_cond_wait()からの戻り値は、この述部の値について何も意味しないため、このような戻り時に述部を再評価する必要があります。

そう、 pthread_cond_waitは、通知していない場合でも返すことができます。少なくとも一見すると、それはかなりひどいようです。それは、間違った値をランダムに返すか、実際に適切なreturnステートメントに到達する前にランダムに返される関数のようなものです。大きなバグのようです。しかし、修正するのではなくマニュアルページでこれを文書化することを選択したという事実は、pthread_cond_waitは、誤って目覚めることになります。おそらく、それが役に立たないようにするために、それがどのように機能するかについて本質的なものがあります。問題は何ですか。

理由pthread_cond_wait誤って戻る?適切に信号が送られた場合にのみウェイクアップすることを保証できないのはなぜですか?誰もがその偽の動作の理由を説明できますか?

131

以下の説明は、David R. Butenhofが "POSIXスレッドを使用したプログラミング" (p。80)で提供しています。

スプリアスウェイクアップは奇妙に聞こえるかもしれませんが、一部のマルチプロセッサシステムでは、コンディションウェイクアップを完全に予測可能にすることで、すべてのコンディション変数操作が大幅に遅くなる場合があります。

次の comp.programming.threadsディスカッション で、彼は設計の背後にある考え方について詳しく説明しています。

 Patrick Doyleが書いた:
>記事では、Tom Payneが書いた:
>> Kaz Kylhekuが書いた:
>>:それは、実装が時々避けられないからです挿入
>>:これらの偽のウェイクアップ。それらを防ぐには費用がかかるかもしれません。 
 
>>しかし、なぜですか?なぜこんなに難しいのですか?たとえば、
>>信号が到着すると同時に待機がタイムアウトする状況について話しているのでしょうか? 
 
>ご存知のように、pthreadの設計者は次のようなロジックを使用していたのでしょうか:
>条件変数のユーザーは、とにかく終了時に条件をチェックする必要があります、
 > 
>スプリアスウェイクアップを許可する場合、追加の負担をかけることはありません。また、スプリアス
>ウェイクアップを許可すると実装を高速化できると考えられるため、
>を許可した場合にのみ役立ちます。 
 
>特定の実装を念頭に置いていなかった可能性があります。 
 
十分に遠くまでプッシュしなかった場合を除いて、実際にはそれほど遠くありません。 
 
意図は、述語ループを要求することにより、正しい/堅牢なコードを強制することでした。これは
ワーキンググループの「コアスレッド」の中の証明可能な正しい学問的条件によって推進されましたが、理解した上で
意図に本当に反対した人はいないと思いますそれが意味すること。 
 
その意図に従い、いくつかのレベルの正当化を行いました。 1つ目は、
「厳密に」ループを使用することで、アプリケーションを独自の不完全な
コーディング慣行から保護することです。 2番目は、
同期メカニズムを最適化することにより、平均条件待機操作のパフォーマンスを改善する
マシンと実装コードを抽象的に想像することは困難ではなかったことです。 。 
/------------------ [David.Buten ... @ compaq.com] -------------- ----\
 | Compaq Computer Corporation POSIXスレッドアーキテクト| 
 |私の本:http://www.awl.com/cseng/titles/0-201-63392-2/ | 
\----- [http://home.earthlink.net/~anneart/family/dave.html] -----/
 
73
NPE

「スプリアスウェイクアップ」には、少なくとも2つの意味があります。

  • pthread_cond_waitでブロックされたスレッドは、条件に関するシグナルまたはブロードキャストの呼び出しが発生していなくても、呼び出しから戻ることができます。
  • pthread_cond_waitでブロックされたスレッドは、シグナルまたはブロードキャストの呼び出しのために戻りますが、mutexを再取得した後、基礎となる述部はもはや真ではないことがわかります。

ただし、条件変数の実装で前者のケースが許可されていない場合でも、後者のケースが発生する可能性があります。プロデューサーとコンシューマーのキュー、および3つのスレッドを考えます。

  • スレッド1はエレメントをデキューし、mutexを解放したばかりで、キューは空になりました。スレッドは、何らかのCPUで取得した要素で行うことをすべて実行しています。
  • スレッド2はエレメントをデキューしようとしますが、ミューテックスでチェックされるとキューが空であることを検出し、pthread_cond_waitを呼び出し、コール待機中のシグナル/ブロードキャストをブロックします。
  • スレッド3はミューテックスを取得し、新しい要素をキューに挿入し、条件変数に通知して、ロックを解除します。
  • スレッド3からの通知に応じて、条件を待機していたスレッド2が実行されるようにスケジュールされます。
  • ただし、スレッド2がCPUにアクセスしてキューロックを取得する前に、スレッド1は現在のタスクを完了し、さらに作業を行うためにキューに戻ります。キューロックを取得し、述語をチェックして、キューに作業があることを見つけます。スレッド3が挿入したアイテムをデキューし、ロックを解除し、スレッド3がキューに入れたアイテムに対して行う処理をすべて実行します。
  • スレッド2はCPUにアクセスしてロックを取得しますが、述語をチェックすると、キューが空であることがわかります。スレッド1がアイテムを「盗んだ」ので、ウェイクアップは見せかけのように見えます。スレッド2は条件を再度待機する必要があります。

したがって、ループの下で述部を常にチェックする必要があるため、基礎となる条件変数に他の種類のスプリアスウェイクアップが含まれていても違いはありません。

95
acm

pthread_cond_signal の「条件信号による複数の目覚め」セクションには、スプリアスwakekupsを伴うpthread_cond_waitおよびpthread_cond_signalの実装例があります。

7
Jingguo Yao