1

VS 2012、.Net 4.5 を使用しています。

このコードを実行します (スレッドに関する記事からいくつかのサンプルをアップグレードするだけです)。

using System.Threading;
class BasicWaitHandle
{
static EventWaitHandle wh = new AutoResetEvent(false);

static void Main()
{
    new Thread(Waiter).Start();
    new Thread(Waiter).Start();
    Thread.Sleep(1000);                 // Подождать некоторое время...
    wh.Set();                            // OK – можно разбудить
    wh.Set();
    Console.ReadLine();
}

static void Waiter()
{
    Console.WriteLine("Avait..."+Thread.CurrentThread.ManagedThreadId);
    wh.WaitOne();                        // Ожидать сигнала
    Console.WriteLine("Got a signal"+Thread.CurrentThread.ManagedThreadId);
}
}

私はそれを数回デバッグしますが、通常 (常にではありません) 間違った結果が得られます。最初に(1回以上)修正します:

Avait...10
Avait...11
Got a signal 11
Got a signal 10

しかし、その後、1 つのスレッドをスキップし始めます (最初の場合もあれば、2 番目の場合もあります)。

Avait...10
Avait...11
Got a signal 11 (or 10)

そして、プログラムは反応しません。数分で正しい結果が得られますが、再び間違った結果が得られます...

さらに、段階的にデバッグすると、常に正しく動作します。

だから、多分私は別のアプローチを選ぶべきですか?しかし、スレッドがランダムな順序でシグナルを受け取ったとしても、これは私が期待したように見えます...

4

2 に答える 2

0

両方のスレッドが開始され、WaitHandle でブロックされるまで実行されます。WaitHandle が設定されると、1 つのスレッドが起動し、イベントがリセットされます。

どのスレッドが起動するかは保証できないため、順序は保証されません。正しく実行されている場合、毎回 10 または 11 のいずれかが起動し、続いてもう一方が起動します。

アプリケーションがハングする場合、問題は実行順序です。メイン スレッドは、最初のスレッドが起動する前に Event.Set() への両方の呼び出しを実行しています。AutoResetEvent はカウンターではなく、設定または設定解除されるため、Set() の 2 回目の呼び出しは失われます。

Set() の呼び出しの間に Sleep() すると、他のスレッドに譲歩し、そのうちの 1 つにウェイクアップしてイベントをリセットする時間を与えます。

正しく動作する場合は、運が良かっただけで、待機中のスレッドが Set() の呼び出しの間に実行される可能性があります。これは競合状態と呼ばれます。

于 2014-01-13T15:23:10.373 に答える