简体   繁体   English

Console.ReadKey与带有Timer的Console.ReadLine

[英]Console.ReadKey vs Console.ReadLine with a Timer

The following code is a well known example to show the difference between a debug and release build: 以下代码是一个众所周知的示例,用于显示调试版本和发布版本之间的区别:

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

If you run this with a debug configuration, the timer will output the current time every two seconds. 如果使用调试配置运行此命令,则计时器将每两秒输出当前时间。 The GC.Collect doesn't have any effect because the compiler artificially extends the life of the Timer t variable. GC.Collect没有任何影响,因为编译器人为地延长了Timer t变量的寿命。 In a release configuration, the timer will execute only once. 在发布配置中,计时器只执行一次。 The GC.Collect will garbage collect the t variable and that's it. GC.Collect将垃圾收集t变量,就是这样。

This all works like it should. 一切都像它应该的那样。 The strange thing is, when you change the line Console.ReadLine to Console.ReadKey both configurations run the timer every two seconds. 奇怪的是,当您将Console.ReadLine行更改为Console.ReadKey时, 两个配置每两秒运行一次计时器。

What is the difference between Console.ReadKey and Console.ReadLine? Console.ReadKey和Console.ReadLine有什么区别? I understood from the documentation that Console.ReadKey blocks the thread issuing the ReadKey method. 从文档中了解到Console.ReadKey阻塞了发出ReadKey方法的线程。 But the GC.Collect still fires.. 但是GC.Collect仍然会发射..

Why is the lifetime of Timer t extended by blocking the main thread? 为什么通过阻塞主线程来延长Timer t的生命周期?

Update 更新

When using .NET 3.5, this behavior won't occur! 使用.NET 3.5时,不会发生此行为!

The Console.ReadKey() method locks the Console.InternalSyncObject whereas the Console.ReadLine() method does not. Console.ReadKey()方法锁定Console.InternalSyncObjectConsole.ReadLine()方法则不锁定。 When the TimerCallBack() method tries to write to the Console the Thread waits because the Console.InternalSyncObject is still locked. TimerCallBack()方法尝试写入ConsoleThread等待,因为Console.InternalSyncObject仍然被锁定。 Therefore GC.Collect() is never called. 因此从不调用GC.Collect() As soon as you hit a key the lock is released and GC.Collect() is called. 只要按下某个键,就会释放锁定并GC.Collect()

I changed your code to the following which doesn't lock the Console.InternalSyncObject and it only beeps once in Release and every 2 seconds in Debug. 我将您的代码更改为以下内容,该代码不会锁定Console.InternalSyncObject ,它只在Release中发出一次哔声,在Debug中每2秒发出一次。

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

The reason the Console.WriteLine() waits is because it tries to acquire a lock on the Console.InternalSyncObject when creating the Console.Out TextWriter for the first time. Console.WriteLine()等待的原因是它在第一次创建Console.Out TextWriter时尝试获取Console.InternalSyncObject上的锁。

Changing your code to the following works as expected as we create the Console.Out TextWriter before starting the timer. 在我们在启动计时器之前创建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();
}

This is due to a change in .NET 4.5. 这是由于.NET 4.5的变化。 More info here 更多信息在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM