13

次のコードは、デバッグ ビルドとリリース ビルドの違いを示すよく知られた例です。

using System;
using System.Threading;

public static class Program
{
    public static void Main()
    {
        Timer t = new Timer(TimerCallback, null, 0, 2000);
        Console.ReadLine();
    }

    private static void TimerCallback(Object o)
    {
        Console.WriteLine("In TimerCallback: " + DateTime.Now);
        GC.Collect();
    }
}

これをデバッグ構成で実行すると、タイマーは現在の時刻を 2 秒ごとに出力します。コンパイラは人為的に変数の寿命を延ばすため、これは何のGC.Collect効果もありません。Timer tリリース構成では、タイマーは 1 回だけ実行されます。は変数GC.Collectをガベージ コレクションし、それだけです。t

これはすべて正常に機能します。奇妙なことに、行 Console.ReadLine を Console.ReadKey に変更すると、両方の構成で 2 秒ごとにタイマーが実行されます。

Console.ReadKey と Console.ReadLine の違いは何ですか? Console.ReadKey が ReadKey メソッドを発行するスレッドをブロックすることをドキュメントから理解しました。しかし、GC.Collect は引き続き起動します。

Timer tメインスレッドをブロックすることで の寿命が延びるのはなぜですか?

アップデート

.NET 3.5 を使用している場合、この動作は発生しません。

4

1 に答える 1

10

Console.ReadKey()メソッドはロックしConsole.InternalSyncObjectますが、メソッドはロックConsole.ReadLine()しません。TimerCallBack()メソッドが に書き込もうとすると、がまだロックされているConsoleためThread待機します。Console.InternalSyncObjectしたがってGC.Collect()、呼び出されることはありません。キーを押すとすぐにロックが解除され、GC.Collect()呼び出されます。

コードを次のように変更しました。これはロックせずConsole.InternalSyncObject、リリースでは 1 回、デバッグでは 2 秒ごとにビープ音を鳴らします。

private static void TimerCallback(Object o)
{
    Console.Beep();
    GC.Collect();
}

Console.WriteLine() が待機する理由は、 を初めてConsole.InternalSyncObject作成するときにのロックを取得しようとするためです。Console.Out TextWriter

Console.Out TextWriterコードを次のように変更すると、タイマーを開始する前にを作成するため、期待どおりに機能します。

public static void Main()
{
    Console.WriteLine("Loaded");
    Timer t = new Timer(TimerCallback, null, 0, 2000);
    Console.ReadKey();
}

private static void TimerCallback(Object o)
{
    Console.WriteLine("In TimerCallback: " + DateTime.Now);
    GC.Collect();
}

これは、.NET 4.5 の変更によるものです。詳細はこちら

于 2013-03-28T11:37:58.850 に答える