48

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);
}

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

4

5 に答える 5

65

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

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

したがって、条件変数は、状態が変更されたことを関係者に通知するのに適しています。ミューテックスを取得し、状態を変更し、条件を通知(またはブロードキャスト)して、ミューテックスを解放します。これがあなたの問題を説明しているなら、あなたはcondvar領域にいます。さまざまなリスナーがさまざまな状態に関心がある場合は、ブロードキャストするだけで、それぞれが順番にウェイクアップし、目的の状態が見つかったかどうかを確認します。そうでない場合は、もう一度待ちます。

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

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

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

于 2008-09-20T18:21:54.963 に答える
20

条件分岐を使用すると、セマフォでは実行できないいくつかのことを実行できます。

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

条件変数を使用すると、条件変数を待機しているすべてのスレッドが を介して処理を進めることもできますpthread_cond_broadcastさらに、時間指定の待機を実行できるため、永遠に待機することはありません。

もちろん、条件変数が必要ない場合もあるため、要件によっては、どちらかが優れている場合があります。

于 2008-09-16T11:15:15.233 に答える
5

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

他の回答には、相対的なメリットについての良い議論があります。pthread_cond_broadcastそれが条件変数の明らかな利点であることを付け加えておきます。

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

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

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

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

于 2009-01-12T09:11:45.853 に答える
0

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

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

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

于 2008-09-16T10:10:46.403 に答える
0
while(cam->status == WAIT_DISPLAY) {
    sem_wait(&some_semaphore);
}

これは完全に間違っています。これは競合状態になりやすいです。スレッドが sem_Wait でブロックするまでに、状態 cam->status == WAIT_DISPLAY がシステムで適切に保持されない可能性があります。これは、他のスレッドによって変更された可能性があるためです。そのため、スレッドはすべての間違った理由でスリープ状態になりました。

于 2022-02-28T06:40:00.257 に答える