Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. In a release configuration, the timer will execute only once. The GC.Collect will garbage collect the t variable and that's it.

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.

What is the difference between Console.ReadKey and Console.ReadLine? I understood from the documentation that Console.ReadKey blocks the thread issuing the ReadKey method. But the GC.Collect still fires..

Why is the lifetime of Timer t extended by blocking the main thread?

Update

When using .NET 3.5, this behavior won't occur!

like image 259
Wouter de Kort Avatar asked Mar 28 '13 10:03

Wouter de Kort


People also ask

What is the difference between console ReadLine and console ReadKey?

Difference between ReadLine(), Read(), ReadKey() in C# As MSDN is actually pretty clear. Reads the next line of characters from the standard input stream. simply you can say, it read all the characters from user input. (and finish when press enter).

What does console ReadKey mean?

ReadKey() Method makes the program wait for a key press and it prevents the screen until a key is pressed. In short, it obtains the next character or any key pressed by the user. The pressed key is displayed in the console window(if any input process will happen).

What is the use of ReadKey?

One of the most common uses of the ReadKey() method is to halt program execution until the user presses a key and the app either terminates or displays an additional window of information. The following example uses the ReadKey() method to wait for the user to press the Enter key before terminating the app.

What is the use of console ReadLine () in C#?

The C# readline method is mainly used to read the complete string until the user presses the Enter key or a newline character is found. Using this method, each line from the standard data input stream can be read. It is also used to pause the console so that the user can take a look at the output.


1 Answers

The Console.ReadKey() method locks the Console.InternalSyncObject whereas the Console.ReadLine() method does not. When the TimerCallBack() method tries to write to the Console the Thread waits because the Console.InternalSyncObject is still locked. Therefore GC.Collect() is never called. As soon as you hit a key the lock is released and GC.Collect() is called.

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.

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.

Changing your code to the following works as expected as we create the Console.Out TextWriter before starting the timer.

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. More info here

like image 175
Alex Wiese Avatar answered Oct 20 '22 09:10

Alex Wiese