A colleague of mine found an issue with our code and it took a while to hunt down exactly what was happening, but it can be best demonstrated by this simple example:
// Fails
class Program
{
static void Main(string[] args)
{
Task.Run(() => Console.WriteLine("Hello World"));
Console.ReadKey();
}
}
// Works fine
class Program
{
static void Main(string[] args)
{
Console.Write(String.Empty);
Task.Run(() => Console.WriteLine("Hello World"));
Console.ReadKey();
}
}
It’s clear from playing around with this that writing to the console anywhere from the main thread will allow the background thread to write to the console also, but we are struggling to understand why this is happening. Can anyone explain what writing to the console from the main thread achieves that the first snippet does not?
The Task. Run method is used to run CPU-bound code concurrently; ideally in parallel. It queues the specified work to run on the ThreadPool and returns a task or Task<TResult> handle for that work. . NET contains numerous methods such as StreamReader.
The Run method allows you to create and execute a task in a single method call and is a simpler alternative to the StartNew method. It creates a task with the following default values: Its cancellation token is CancellationToken.
NET code does not mean there are separate new threads involved. Generally when using Task. Run() or similar constructs, a task runs on a separate thread (mostly a managed thread-pool one), managed by the . NET CLR.
What Is A Task In C#? A task in C# is used to implement Task-based Asynchronous Programming and was introduced with the . NET Framework 4. The Task object is typically executed asynchronously on a thread pool thread rather than synchronously on the main thread of the application.
I have a suspicion as to what's going on. What I've observed:
ReadKey
, it's fine. This includes fetching Console.Out
but not using itConsole.WriteLine
call starts before the Console.ReadKey
call, it's fine (and you can have multiple WriteLine
calls while ReadKey
is waitingI suspect that the first operation to use the console acquires a lock for initialization (to avoid it being initialized twice) and that the ReadKey
method keeps hold of the lock until a key has been read. That would certainly explain every program I've run so far.
The operations which perform the hypothesized initialization are interesting though - reading Console.Out
"fixes" the issue, but reading from Console.In
doesn't.
I suspect that ReadKey
initializes the output because the value is still echoed to the console... but I wouldn't like to swear to it.
Interestingly, using Console.ReadLine()
instead of Console.ReadKey()
doesn't cause the problem in the first place.
Actually, the first case doesn't fail. "Hello World" appears just before the Application ends. This is a classical Race Condition. In the first case,Console.ReadKey()
from the main thread beats the task, and in the second case, the task wins. Unfortunately, I cannot tell you Exactly why writing the empty string makes the task win.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With