2

タイトルは基本的にそれ自体を物語っています。特定の条件とミューテックスで pthread_cond_wait を呼び出した場合、対応する条件で pthread_cond_signal が呼び出されるまで、そのスレッドはブロックされたままになりますか? それとも、後でミューテックスが再びロック解除されても、ブロックは解除されますか?

答えが前者の場合、フォローアップがあります。スレッド間のメッセージ パッシングに使用するキューがあります。一度に 1 つのスレッドだけが項目をキューに追加できるようにしたい (したがって、ミューテックスを使用する)。他のスレッドがミューテックス自体を取得するのを待っているかどうかは、どのスレッドにもわかりません。

アイテムをキューに追加しようとすると、ミューテックスをロックし、pthread 条件でキューがいっぱいになるのを待ってから追加を実行し、ミューテックスをロック解除します。ロックを解除する前に、他のスレッドが待機しているかどうかわからなくても、pthread_cond_signal を実行する必要がありますか? 複数のスレッドが待機している場合はどうなりますか?

4

4 に答える 4

6
  1. 誰かが条件変数を通知/ブロードキャストする必要があります。そうしないと、待機中のスレッドが必ずしも起動されるとは限りません。「偽の」ウェイクアップを取得することもできますが、それらに依存しないでください。ウェイターが (シグナル、ブロードキャスト、または誤って) 起こされると、ミューテックスの取得を試み始め、それが返されると、それが返され pthread_cond_waitます。

  2. 複数のスレッドが待機している場合は、そのうちの 1 つが (任意に、または実装によって文書化されたルールに従って) 起動されます。あなたが説明したコードでは、スレッドがこの condvar で待機する唯一の場所は、完全なキューにアイテムを追加しようとしているときです。したがって、次の 3 つのオプションがあります。

    • いっぱいになったキューから要素を削除するたびに、条件変数にシグナルを送ります。これにより、0 個以上のウェイターの 1 つがウェイクアップされます。次に、複数のウェイターがあった場合に備えて、キューがまだいっぱいでない場合は、要素を追加した後に再度シグナルを送信します。

    • フルキューから要素を削除するたびに、条件変数をブロードキャストします。要素を追加した後にシグナルを送る必要がなくなりました。

    • キューがいっぱいかどうかに関係なく、要素を削除するたびに条件変数にシグナルを送ります。これを行う場合は、コードを変更して一度に 2 つの要素を削除し、シグナルを 1 回だけにするという間違いを犯さないでください。条件変数は、シグナルを送信するたびにウェイターの数を 1 つずつ減らします。このアプローチは、少なくとも 1 つのウェイターが同時に存在することを防ぎ、ミューテックスを取得しようとするウェイクされた元ウェイターの数がキュー内のスペースよりも少ないため、機能しますそのため、スレッドが使用できるスペースがあるときにスレッドを待機させることはありません。

これを考える方法は、あなたが待っている「条件」は「キューがいっぱいではない」ということです。条件が真になるたびに、条件変数を通知またはブロードキャストする必要があります。シグナルを送ることを選択し、複数のウェイターが存在する可能性がある場合、各ウェイターは、その処理が完了した後も条件が trueのままである場合に (次のウェイターを起こすために) シグナルを送信する必要があります。

いくつかの余分なコンテキスト スイッチのパフォーマンス コストを気にせず、偽の wakes に対処するために condvar を正しく待機するコードを記述している場合は、状態がまだ偽。これは、条件変数の優れた点の 1 つであり、コードの正確性を判断しやすくなります。したがって、「条件が真になるたびに、条件変数を通知またはブロードキャストする必要がある」という要件は、それが示すことだけを意味します。条件が true になった場合にのみ通知する必要はありません。

したがって、この場合、事前に満杯であったかどうかに関係なく、要素をキューから削除するたびに通知することは問題ありません。この場合、シグナルの数を必要最小限に減らすのは簡単ですが、条件が true になったかどうかを確認するのは価値があるよりも面倒な場合があるため、代わりに、現在 true であるかどうかを通知します。以前は偽だった、または今は真である可能性があるかどうかを示すだけです。理由もなく追加の wakes を追加することはお勧めしませんが、コードが単純になる場合があります。

于 2012-11-07T16:05:30.227 に答える
1

pthread_cond_waita)条件変数が通知され、b)他のスレッドがミューテックスのロックを解除すると、この呼び出しのブロックが解除されます。次にpthread_cond_wait、ミューテックスをロックして戻ります。

(ほとんどの場合、戻った後、「キューはいっぱいですか?」などの実際のテストを再確認する必要があることに注意してくださいpthread_cond_wait。通常while、その理由でループで呼び出します。)

pthread APIを使用して、他のスレッドが条件変数を待機しているかどうかを確認できないため、通常のパターンは、ミューテックスのロックを解除する前に呼び出すことpthread_cond_signalです。pthread_cond_broadcast誰も待っていなければ、これらは安いです。

「シグナル」と「ブロードキャスト」の違いは、前者は1つの待機中のスレッドのみをウェイクアップし(どちらが指定されていないか)、後者はすべてのスレッドをウェイクアップすることです。

あなたの場合、キューからアイテムを削除するたびに「ブロードキャスト」して、挿入スレッドにショットがあることを知らせる必要があると思います。そうすれば、他のインサートからスレッドを挿入するように通知する必要はありません。

于 2012-11-07T16:07:08.553 に答える
1

アイテムをキューに入れるとき、キューが以前に空だった場合は条件変数にシグナルを送信します。これにより、キューからアイテムを取得するのを待つ可能性のあるスレッドを起動できます。キューが空でない場合、フェッチ中のスレッドが条件でブロックされる理由はないため、シグナルは必要ありません。

キューからアイテムをフェッチするとき、キューが以前に完全にいっぱいだった場合は、別の条件変数を通知します。これにより、アイテムをキューに入れるのを待つ可能性のあるスレッドを起動できます。キューがいっぱいでない場合、追加スレッドが条件でブロックされる理由はないため、シグナルは必要ありません。

キューとの間で複数のアイテムを取得/配置しない限り、ブロードキャストしないでください。アイテムを1つだけ入れる場合は、それぞれ。1 つのスロットだけを利用できるようにしてブロードキャストすると、すべてのスレッドが起動しますが、進行できるのは 1 つだけです。他のすべてのスレッドは待機して起動し、再開してスリープ状態に戻るのは純粋なスレッドになります。オーバーヘッド。

于 2012-11-07T16:22:05.663 に答える
0

1 はい。への呼び出しに関連付けられたミューテックスpthread_cond_wait()は、関数によってロック解除されます。

2 条件で待機しているスレッドは再開できます。戻ると、関連するpthread_cond_wait()ミューテックスがロックされます。

pthread_cond_wait

(pthread_unlock_mutex に従って)ミューテックスをアトミックにロック解除し、条件変数 cond が通知されるのを待ちます。スレッドの実行は中断され、条件変数が通知されるまで CPU 時間を消費しません。ミューテックスは、pthread_cond_wait への入り口で、呼び出し元のスレッドによってロックされている必要があります。呼び出しスレッドに戻る前に、pthread_cond_wait はミューテックスを再取得します(pthread_lock_mutex に従って)。

于 2012-11-07T15:46:37.050 に答える