1

Monitor.Pulseおよび PulseAll では、操作対象のロックが呼び出し時にロックされている必要があります。この要件は不必要であり、パフォーマンスに悪影響を及ぼします。私の最初のアイデアは、これにより 2 つの無駄なコンテキスト スイッチが発生するというものでしたが、これは以下の nobugz によって修正されました (ありがとう)。モニターで待機していた他のスレッドが既にシェデュラーで使用可能であるため、コンテキスト スイッチが無駄になる可能性があるかどうかはまだわかりませんが、それらがスケジュールされている場合は、いくつかの命令しか実行できません。ミューテックスにヒットする前に、コンテキストを再度切り替える必要があります。Monitor.Pulse を呼び出す前にロックが解除されていれば、これははるかに単純で高速に見えます。

Pthread 条件変数は同じ概念を実装しますが、上記の制限はありません。ミューテックスを所有していなくても pthread_cond_broadcast を呼び出すことができます。これは、要件が正当化されていないことの証拠だと思います。

編集: Monitor.Pulse の前に通常変更される共有リソースを保護するには、ロックが必要であることを認識しています。モニターがこれをサポートしていることを考えると、リソースへのアクセス後、パルスの前にロックが解除された可能性があると言いたかったのです。これは、共有リソースがアクセスされる最短時間にロックを制限するのに役立ちます。そのような:

void f(Item i)
{
  lock(somequeue) {
    somequeue.add(i);
  }
  Monitor.Pulse(somequeue);  // error
}
4

4 に答える 4

2

その理由は、メモリ バリアとスレッド セーフの保証に関係しています。

Pulse() が必要かどうかを判断するために使用される共有変数 (条件) は、関連するすべてのスレッドによってチェックされます。メモリ バリアがないと、変更がレジスタに保持され、スレッド間で認識されない可能性があります。読み取りと書き込みは、スレッド間で表示するときに並べ替えることもできます。

ただし、ロック内からアクセスされる変数はメモリ バリアを使用するため、関連するすべてのスレッドからアクセスできます。ロック内のすべての操作は、同じロックを保持している他のスレッドから見ると、アトミックに実行されているように見えます。

また、仮定したように、複数のコンテキスト スイッチは必要ありません。待機中のスレッドは (通常は FIFO) キューに入れられ、Pulse() でトリガーされている間は、ロックが解放されるまで完全には実行できません (これもメモリ バリアが原因の 1 つです)。

問題の詳細については、http: //www.albahari.com/threading/part4.aspx#_Wait_and_Pulseを参照してください。

于 2009-12-24T13:41:19.907 に答える
2

Pulse() 呼び出しがスレッド スイッチを呼び出すという仮定は正しくありません。スレッドを待機キューから準備完了キューに移動するだけです。Exit() 呼び出しは、準備完了キューの最初のスレッドに切り替えます。

于 2009-12-24T16:11:42.143 に答える
1

私はこの論文で答えを見つけました:

http://research.microsoft.com/pubs/64242/implementingcvs.pdf

それは述べています:

このレベルのスレッドの実装を検討しているので、最後にもう 1 つのパフォーマンスの問題と、その対処方法を指摘する必要があります。ロック m が保持された状態で Signal が呼び出され、マルチプロセッサで実行している場合、新しく起動されたスレッドはすぐに実行を開始する可能性が非常に高くなります。これにより、m をロックしたいときに (2) で数命令後に再びブロックされます。これらの余分な再スケジュールを回避したい場合は、スレッドを条件変数キューから m を待っているスレッドのキューに直接転送するように手配する必要があります。これは、Signal または Broadcast を呼び出すときに m を保持する必要がある Java または C# で特に重要です。

この論文は全体として少し曖昧であり、多くの実装の詳細については言及されていません。むしろ疑似/学術レベルです。しかし、それを書いた人たちは、実際の .net 実装に責任を持っていたようです。

しかし大まかに言えば、シグナルは単なる論理/ユーザーレベルの操作であり、条件変数シグナルのようなプリミティブをすぐには起動しません。ロックスコープ出口でのみそうします。したがって、パフォーマンスの問題はありません。実際、条件変数を直接操作するために使用されると、本当に気がかりです。

于 2013-02-21T09:48:20.640 に答える
0

Wait は、条件付きチェックで使用するように設計されています。条件付きチェックがロック内で行われなかった場合、次の一連のイベントが発生する可能性があります。

  1. 条件チェックは、待機が必要であることを示しています。
  2. 別のスレッドが条件を変更して待機が不要になり、Pulse または PulseAll を実行します。
  3. 待機が必要であることを確認した最初のスレッドは、待機を実行します。

その一連のイベントが発生すると、再びロックをパルスすることはまったくありません (待機が再び必要になり、再び必要でなくなる状況が発生しない限り)。したがって、スレッド #1 は、決して到着しないイベントを永久に待機する可能性があります。

条件チェックと待機をロック内に置くと、この危険が回避されます。これは、条件がチェックされてから待機が開始されるまでの間、別のスレッドが条件を変更する方法がないためです。したがって、Condition を変更して Pulse を実行する別のスレッドは、最初のスレッドが変更後に条件をチェックした (したがって待機を回避した) か、Pulse が実行されたときに Wait を実行していた (したがって再開できた) ことを保証できます。 )。

于 2011-01-21T20:21:08.403 に答える