2

ネタバレ注意:質問は最後のフレーズです。

C#では、条件変数を使用する従来のパターンは次のようになります。

lock (answersQueue)
{
    answersQueue.Enqueue(c);
    Monitor.Pulse(answersQueue); // condition variable "notify one".
}

およびその他のスレッド:

lock (answersQueue)
{
    while (answersQueue.Count == 0)
    {
        // unlock answer queue and sleeps here until notified.
        Monitor.Wait(answersQueue);
    }
    ...
}

これは私のコードから抜粋した例です。パルスをロックスコープの外に置くと、コンパイルされません。ただし、これは正しい方法です。cf:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686903(v=vs.85).aspx および: http: //www.installsetupconfig.com/win32programming/threadprocesssynchronizationapis11_7.html ( "中身")

そして確かに、あなたがまだクリティカルセクションにいるときに眠っているスレッドに合図するのはばかげています。スリーピングスレッドは(すぐにではなく)ウェイクアップできないため、批判的なセクションの内側にもあるためです!

したがって、.NETまたはC#のPulse呼び出しが実際にはロックオブジェクトにフラグを立てているだけで、スコープ外になると、この時点で条件変数を実際に「パルス」することを願っています。そうしないと、最適性の問題が発生するためです。

では、なぜMonitorオブジェクトのデザインがそのように選択されたのでしょうか。

編集:

私はこの論文で答えを見つけました: http ://research.microsoft.com/pubs/64242/implementingcvs.pdf セクション「信号とブロードキャストの最適化」とNTカーネルに関する前のセクションとセマフォの上に条件変数を作成する方法、これが「ダーンドキュー」を導入する理由です。今ではそれが私をより良いエンジニアにします。

4

2 に答える 2

1

そして確かに、あなたがまだクリティカルセクションにいるときに眠っているスレッドに合図するのはばかげています。眠っている糸は目を覚ますことができないので

Pulse スレッドが実行されることを期待していません。2つのキュー(待機中と準備完了)の間でスレッドを移動することだけを想定しています。「何かをしない」は、を介してExit(またはの終わりにlock)ロックを解除することの一部です。通常、またはのMonitor.Pulse直前に発生するため、実際には問題にはなりません。WaitExit

したがって、.NETまたはC#のPulse呼び出しが実際にはロックオブジェクトにフラグを立てているだけで、スコープ外になると、この時点で条件変数を実際に「パルス」することを願っています。そうしないと、最適性の問題が発生するためです。

また; これらは異なる問題です。待機と準備の間を移動することは1つのことです。ロックを終了すると、次の準備ができたスレッドを実際にアクティブ化するためのすべてのコードがすでに含まれています。

于 2013-02-01T10:07:20.403 に答える
1

あなたは同期の基本的な問題を理解していませんでした。「モニター」とは何ですか、スレッドがスリープしているとはどういう意味ですか?また、スレッドが起こされようとしているとはどういう意味ですか?

モニターは、中間レベルの同期構造です。これは、バス停止XCHG操作を伴う低レベルのささいな揮発性ブールフラグではなく、他の数十の特別なメカニズムを必要とする高レベルのスレッドプールハンドラーでもありません。

モニターでは、多くのスレッドがスリープする可能性があります。そこには論理的な待ち行列があります。つまり、スリープ/ウェイクアップの保存順序、または適切な時間スケジューリングとフェアニーを保証するメカニズムです。詳細については説明しません。すべては、ウィキでもWeb上にあります。

それに加えて、操作はPULSEです。パルスは瞬時です。「くっつく」ことはありません。パルスは今眠っている人を目覚めさせます。パルスの後に別の1つがモニターをチェックすると、モニターはスリープ状態になります。

ここで想像してみてください。5つのスリープスレッドのキューがあります。1つのスレッド(6番目)がそれらをパルスしたいと考えており、さらに別のスレッド(7番目)がモニターをチェックしたいと考えています。

クアッドコアCPUを使用しているため、6番目と7番目は並行して実行されています。

では、6番目がパルスを開始し、ウェイクアップしてキューからウェイクアップされたスレッドを削除し、同時に7番目のスレッドがキューに追加し始めた場合、キューの実装はどうなるでしょうか。

これを解決するには、内部キューを内部で同期してロックする必要があるため、一度に1つのスレッドのみがそれらを変更します。

ちょっと待って。何かを同期したい場合に遭遇しました。それを適切に行うには、別のことを同期する必要がありますか?良くない。

したがって、実際のLOCKは、モニター自体に話しかける前に外部で実行されます。これは、階層ロックの複数のレイヤーを導入するのではなく、シングルロックを実現するためです。

そうすれば、よりシンプルで、より速く、よりリソースに優しいものになります。

于 2013-02-01T10:08:44.997 に答える