Console.ReadKey与带有Timer的Console.ReadLine

时间:2013-03-28 10:42:14

标签: c# multithreading timer console garbage-collection

以下代码是一个众所周知的示例,用于显示调试和发布版本之间的区别:

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();
    }
}

如果使用调试配置运行此命令,计时器将每两秒输出当前时间。 GC.Collect没有任何影响,因为编译器会人为地延长Timer t变量的生命周期。在发布配置中,计时器只执行一次。 GC.Collect将垃圾收集t变量,就是它。

这一切都应该如此运作。奇怪的是,当您将Console.ReadLine行更改为Console.ReadKey 两个配置时,每两秒运行一次计时器。

Console.ReadKey和Console.ReadLine有什么区别?我理解from the documentation Console.ReadKey阻塞发出ReadKey方法的线程。但GC.Collect仍然会发射..

为什么通过阻止主线程来延长Timer t的生命周期?

更新

使用.NET 3.5时,不会发生此行为!

1 个答案:

答案 0 :(得分:10)

Console.ReadKey()方法锁定Console.InternalSyncObject,而Console.ReadLine()方法则不锁定TimerCallBack()方法。当Console方法尝试写入ThreadConsole.InternalSyncObject等待,因为GC.Collect()仍处于锁定状态。因此永远不会调用GC.Collect()。只要您按下某个键,锁就会被释放,并且会调用Console.InternalSyncObject

我将您的代码更改为以下内容,但不会锁定private static void TimerCallback(Object o) { Console.Beep(); GC.Collect(); } ,它只会在Release中发出一次哔声,在Debug中每2秒发出一次哔声。

Console.InternalSyncObject

Console.WriteLine()等待的原因是,它在第​​一次创建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(); } 时按预期更改代码。

{{1}}

这是由于.NET 4.5的变化。更多信息here