web-dev-qa-db-ja.com

pthread_cond_waitとセマフォ

pthread_cond_waitの使用またはセマフォの使用の長所と短所は何ですか?私はこのような状態変化を待っています:

pthread_mutex_lock(&cam->video_lock);
while(cam->status == WAIT_DISPLAY) {
    pthread_cond_wait(&cam->video_cond, &cam->video_lock);
}
pthread_mutex_unlock(&cam->video_lock);

適切に初期化されたセマフォを使用すると、次のようにできると思います。

while(cam->status == WAIT_DISPLAY) {
    sem_wait(&some_semaphore);
}

各方法の長所と短所は何ですか?

45
shodanex

セマフォは、他の用途もありますが、生産者-消費者モデルに完全に適しています。プログラムロジックは、待機数に対して適切な数の投稿が行われるようにする責任があります。セマフォを投稿し、まだ誰もそれを待っていない場合、彼らが待っているとき、彼らはすぐに続行します。セマフォのカウント値で説明できるような問題の場合は、セマフォで簡単に解決できます。

条件変数は、いくつかの点で少し寛容です。たとえば、cond_broadcastを使用して、プロデューサーがいくつあるかを知らなくても、すべてのウェイターをウェイクアップできます。また、誰も待機していないcondvarにcond_signalを発行すると、何も起こりません。これは、興味を持つリスナーがいるかどうかわからない場合に適しています。また、リスナーが待機する前にミューテックスを保持した状態を常に確認する必要があるのもそのためです。そうしないと、シグナルを見逃して、次のシグナルまでウェイクアップしない可能性があります。

したがって、条件変数は、状態が変化したことを関係者に通知するのに適しています。ミューテックスを取得し、状態を変更し、condvarにシグナル(またはブロードキャスト)して、ミューテックスを解放します。これがあなたの問題を説明しているなら、あなたはcondvarの領域にいます。さまざまなリスナーがさまざまな状態に関心を持っている場合は、ブロードキャストして、それぞれが順番に目を覚まし、必要な状態を見つけたかどうかを確認し、そうでなければ再度待機します。

ミューテックスとセマフォでこの種のことを試みるのは確かに非常に危険です。問題は、ミューテックスを取得し、いくつかの状態を確認し、セマフォが変更されるのを待つときに発生します。ミューテックスをアトミックに解放してセマフォを待つことができない限り(pthreadではできません)、ミューテックスを保持しながらセマフォを待つことになります。これはミューテックスをブロックします。つまり、他の人はあなたが気にする変更を行うためにそれを取ることができません。したがって、特定の要件に依存する方法で別のミューテックスを追加したくなるでしょう。そして多分別のセマフォ。結果は、一般に、有害な競合状態を伴う不正なコードです。

Cond_waitを呼び出すと自動的にミューテックスが解放され、他の人が使用できるようになるため、条件変数はこの問題を回避します。 mudは、cond_waitが戻る前に回復されます。

IIRCセマフォのみを使用して一種のcondvarを実装することは可能ですが、condvarを使用するために実装しているミューテックスがtrylockを必要とする場合、それは深刻なヘッドスクラッチャーであり、時間待機がなくなります。推奨されません。したがって、condvarで実行できることはすべてセマフォで実行できると想定しないでください。加えて、もちろんミューテックスは、セマフォが欠けている素敵な振る舞い、主に優先順位逆転回避を持つことができます。

62
Steve Jessop

条件文を使用すると、セマフォでは実行できない処理を実行できます。

たとえば、mというミューテックスを必要とするコードがあるとします。ただし、他のスレッドがタスクを完了するまで待機する必要があるため、sというセマフォで待機します。これで、mを含むスレッドがmで待機している場合でも、sを必要とするすべてのスレッドの実行がブロックされます。このような状況は、条件文を使用して解決できます。条件付きで待機すると、現在保持されているミューテックスが解放されるため、他のスレッドがミューテックスを取得できます。したがって、例に戻って、cの代わりに条件付きsが使用されたとします。スレッドがmを取得し、cで条件付き待機します。これによりmが解放されるため、他のスレッドを続行できます。 cが利用可能になると、mが再取得され、元のスレッドはその過程で楽に続行できます。

条件変数を使用すると、_all条件変数を待機しているスレッドがpthread_cond_broadcastを介して処理を続行できるようにすることもできます。さらにtimed waitを実行することもできるので、永久に待機することはありません。

もちろん、条件変数が不要な場合もあるため、要件に応じて、どちらか一方の方が適している場合があります。

19
freespace

2番目のスニペットは際どいです、それをしないでください。

他の回答には、相対的なメリットについての素晴らしい議論があります。追加するだけですpthread_cond_broadcastは、条件変数の明らかな利点です。

それを超えて、共有フラグをチェックする際の競合を回避するのに役立つため、Javaで使用するものであるため、変数の条件付けに慣れています。

実際、2番目のスニペットでは、cam-> statusの読み取りを保護するロックがないため、データレースを通じてアクセスされます。ほとんどのプラットフォームでは、この特定の例ではそれを回避できますが、POSIXおよび次のC/C++標準のメモリモデルによって、セマンティクスは未定義です。

実際、別のスレッドが新しいカム構造を割り当ててカムを上書きすると、実際の競合状態が発生する可能性があります。待機中のスレッドは、cam-> statusの初期化を確認せずに、「cam」ポインタの更新を確認する場合があります。実際、2番目のスニペットは、この場合も一般的にも、問題を求めています。

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

5
Blaisorblade

2番目のスニペットでは、ロックを何度も取得していますが、解放することはありません。

一般に、あなたが監視している状態はセマフォによって完全に表現でき、それをそのまま使用できます。ロック構造はサイズが小さく、チェック/設定/解放に必要なアトミック操作が少なくて済みます。

それ以外の場合、状態が複雑で、コードのさまざまな部分が同じ変数のさまざまな条件で待機している場合(たとえば、ここではx <10が必要ですが、y> xが必要です)、cond_waitを使用します。

0
Javier