4

この問題を説明する最小限のコードを次に示します。

StringBuilder input = new StringBuilder();

void ToUpper()
{
    lock (input)
    {
        while (true)
        {
            Monitor.Wait(input);

            Console.WriteLine(input.ToString().ToUpper());
        }
    }
}

public void Run()
{
    new Thread(ToUpper) { IsBackground = true }.Start();

    // "Avoid" the initial race
    Thread.Sleep(100);

    while (true) 
    {
        lock (input)
        {
            input.Clear();
            input.Append(Console.ReadLine());
            Monitor.Pulse(input);
        }
        // Thread.Sleep(1);
    }
}

よく知られている初期の競合状態を無視すると、Pulse と Wait の動作に驚かされます。

これが私が期待したものです:

  • 「ToUpper」スレッド呼び出しWait=> モニターの待機キューにプッシュされます
  • メインスレッド呼び出しPulse=> 「ToUpper」スレッドが待機キューから準備完了キューに「移動」され、ロックをすぐに取得できるようになります
  • lockメインスレッドは、ステートメントスコープを終了するときにモニターを終了します
  • メインスレッドがロックの所有権を再登録している間に、「ToUpper」スレッドがロックを取得して入力を処理します。

しかし、2 回に 1 回は「ToUpper」スレッドが入力を処理せず、代わりにメイン スレッドがその処理をすぐに実行します

ここに私の仮定があります:

  • Pulse「ToUpper」スレッドをすぐに「移動」しないため、準備完了キューは空のままです
  • メインスレッドがロックを解放し、ループし、再びロックを要求する
  • 準備完了キューには他に誰もいないため、所有権を取得します
  • 後で「ToUpper」スレッドを昇格するためのリクエストが実行され、最終的に準備完了キューにプッシュされることがあります
  • メインスレッドPulseをもう一度何もせずにロックを解放します
  • ループし、ロックを再取得しようとしますが、「ToUpper」スレッドはすでにそこにあります
  • 今回は「ToUpper」スレッドがロックを取得し、入力を処理します
  • 完了すると、次の信号を待って再びスリープします
  • メインスレッドがロックを取得します

この仮定を確認するために、メイン スレッドの熱意を弱め、他のスレッドが機能するようにThread.Sleep(1)=> を追加することで、この場合はすべて「期待どおりに機能する」ようにしました。

Pulseつまり、スレッドを待機キューから準備完了キューにすぐにプッシュしない可能性があるという動作に要約されます。

問題は本当にこのレースの可能性から来ているのでしょうか、それとも私が見逃している別の微妙な点がありますか?

4

1 に答える 1

4

追加についてのあなたの発言Thread.Sleep(1)は本当に答えです。このPulseメソッドは、待機中のオブジェクトに対して何も保証しません。通常のスレッドとして続行する準備完了キューに解放されるだけです。への呼び出しに関する痕跡はどこにもありませんPulse。したがって、呼び出しPulseた後、アプリケーションは通常の 2 スレッド アプリケーションとして動作し、ready キューにはToUpperスレッドスレッドの 2 つのスレッドがありRunます。したがって、スレッドが最初にロックを取得するThread.Sleep(1)ことが発生する可能性はありません (それがなければ、可能性は低いと思います) 。Run

私が提供した2番目のリンクからのもう1つの重要な発言:

Monitor.Pulse の重要な機能は、非同期で実行されることです。つまり、それ自体がブロックまたは一時停止することはありません。

このシナリオでは、AutoResetEventクラスの方が適しているようです。また、2 番目のリンクWaitでは、 と を使用した生産者と消費者のシナリオの例を見つけることができますPulse

于 2013-11-03T12:24:24.103 に答える