11

(以下の項目には異なる目標がありますが、それらがどのように「一時停止」したかを知っているのは興味深いです)

質問

Thread.sleep-システムのパフォーマンスに影響を与えますか?スレッドを待機と結び付けますか?

どう Monitor.Wait ですか?彼らが「待つ」方法の違いは何ですか?彼らは彼らの待機とスレッドを結びますか?

どうRegisteredWaitHandleですか?このメソッドは、待機ハンドルが通知されたときに実行されるデリゲートを受け入れます。待機中は、スレッドを拘束しません。

したがって、一部のスレッドは一時停止され、代理人によって起こされる可能性がありますが、他のスレッドはただ待つだけですか?スピン?

誰かが物事をより明確にしてくれませんか?

編集

http://www.albahari.com/threading/part2.aspx

ここに画像の説明を入力してください

4

5 に答える 5

8

両方ともThread.SleepMonitor.Waitスレッドを次WaitSleepJoin状態にします。

WaitSleepJoin:スレッドがブロックされています。これは、Thread::SleepまたはThread::Joinを呼び出した結果、たとえばMonitor::EnterまたはMonitor::Waitを呼び出してロックを要求した結果、またはManualResetEventなどのスレッド同期オブジェクトを待機した結果である可能性があります。

RegisteredWaitHandleRegisterWaitForSingleObjectを呼び出し、を渡すことによって取得されWaitHandleます。通常、このクラスのすべての子孫はブロッキングメカニズムを使用するため、呼び出すWaitと再びスレッドが挿入されますWaitSleepJoin(例AutoResetEvent)。

これがMSDNからの別の引用です:

RegisterWaitForSingleObjectメソッドは、指定されたオブジェクトのWaitHandleの現在の状態をチェックします。オブジェクトの状態が通知されていない場合、メソッドは待機操作を登録します。待機操作は、スレッドプールのスレッドによって実行されます。オブジェクトの状態が通知されるか、タイムアウト間隔が経過すると、デリゲートはワーカースレッドによって実行されます。

したがって、プール内のスレッドはシグナルを待機します。

于 2012-07-08T08:41:50.360 に答える
6

に関してThreadPool.RegisterWaitForSingleObjectは、これは登録ごとに (プールされているかどうかに関係なく) スレッドを拘束しません。これは簡単にテストできます。LINQPad で次のスクリプトを実行して、そのメソッドを 20,000 回呼び出します。

static ManualResetEvent _starter = new ManualResetEvent (false);

void Main()
{
    var regs = Enumerable.Range (0, 20000)
        .Select (_ => ThreadPool.RegisterWaitForSingleObject (_starter, Go, "Some Data", -1, true))
        .ToArray();

    Thread.Sleep (5000);
    Console.WriteLine ("Signaling worker...");
    _starter.Set();
    Console.ReadLine();

    foreach (var reg in regs) reg.Unregister (_starter);
}

public static void Go (object data, bool timedOut)
{
    Console.WriteLine ("Started - " + data);
    // Perform task...
}

そのコードが 5 秒間の「待機」中に 20,000 のスレッドを拘束した場合、おそらく機能しません。

編集- への応答:

「これは証拠です。しかし、シグナルのみをチェックする単一のスレッドがスレッドプールにまだありますか?」

これは実装の詳細です。はい、コールバックをマネージ スレッド プールにオフロードする単一のスレッドで実装できますが、これが保証されるわけではありません。待機ハンドルは、最終的にはオペレーティング システムによって管理されます。これにより、コールバックもトリガーされる可能性が高くなります。内部実装で 1 つのスレッド (または少数のスレッド) を使用する場合があります。または、割り込みを使用すると、単一のスレッドをブロックしない場合があります。オペレーティング システムのバージョンによっても異なる場合があります。これは、実際には関係のない実装の詳細です。

于 2012-07-09T01:15:26.477 に答える
5

確かにRegisterWaitForSingleObject待機スレッドが作成されますが、すべての呼び出しで待機スレッドが作成されるわけではありません。

MSDNから:

新しい待機スレッドは、必要に応じて自動的に作成されます

Raymond Chen のブログから:

...スレッド全体にコストをかける代わりに、スレッドの 1/64 に近い (ただし正確ではない) コストがかかります

そのRegisterWaitForSingleObjectため、通常は、独自の待機スレッドを作成するよりも使用することをお勧めします。

于 2012-07-09T06:46:05.643 に答える
3

ThreadPool.g RegisterWaitForSingleObject は、ネイティブ実装で最終的に QueueUserAPCを呼び出します。ローターのソース (sscli20\clr\src\vm\win32threadpool.cpp(1981)) を参照してください。Wait Thread.Sleep とは異なり、RegisterWaitForSingleObject を使用すると、スレッドは停止しません。

このスレッドの代わりに、ユーザー モード コールバックを含む FIFO キューが登録されます。これは、スレッドがアラート可能な状態にあるときに呼び出されます。つまり、作業を続けることができ、スレッドがブロックされている場合、OS は登録されたコールバックで動作し、待機中にスレッドが意味のあることを行う機会を与えます。

編集1:

分析を完了する。RegisterWaitForSingleObject を呼び出したスレッドでは、スレッドがアラート可能状態になるとコールバックが呼び出されます。これが発生すると、RegisterWaitForSingleObject を呼び出したスレッドは CLR コールバックを実行します。CLR コールバックは、シグナルされたコールバックを待機するためだけに存在するスレッド プール コールバック待機スレッドによって処理される別のコールバックを登録します。このスレッド プール コールバック待機スレッドは、シグナルされたコールバックを定期的にチェックします。

この待機スレッドは、シグナルされたコールバックがスレッド プール スレッドで実行されるように、最終的に QueueUserWorkItem を呼び出します。

于 2012-07-08T09:27:52.590 に答える