使用Task.Run()写入控制台失败

kev*_*ker 12 c# .net-4.5

我的一位同事在我们的代码中发现了一个问题,并且花了一段时间才能确切地查找正在发生的事情,但最好通过这个简单的例子来证明:

// 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

从中解决这个问题很明显,从主线程到任何地方写入控制台都会允许后台线程写入控制台,但是我们很难理解为什么会发生这种情况.任何人都可以解释从主线程写到控制台的内容是什么,第一个片段没有?

Gab*_*abe 5

实际上,第一种情况并没有失败.应用程序结束前出现"Hello World".这是一个经典的比赛条件.在第一种情况下,Console.ReadKey()从主线程击败任务,在第二种情况下,任务获胜.不幸的是,我无法告诉你究竟为什么写空字符串会让任务获胜.


Jon*_*eet 5

我怀疑发生了什么.我观察到的是:

  • 如果你在开始之前对控制台的输出做了什么ReadKey,那就没关系.这包括获取Console.Out但不使用它
  • 如果你Console.WriteLine拨打一个延迟,以便在通话之前开始Console.ReadKey通话,那就没问题(你可以等待的时候有多个WriteLine电话 ReadKey

我怀疑使用控制台的第一个操作获取初始化锁(以避免它被初始化两次),并且该ReadKey方法保持锁定直到读取了一个键.这肯定会解释我到目前为止所运行的每一个程序.

执行假设初始化的操作虽然很有趣 - 阅读Console.Out"修复"了这个问题,但是从中读取Console.In却没有.

我怀疑ReadKey初始化输出,因为值仍然回显到控制台......但我不想发誓.

有趣的是,使用Console.ReadLine()而不是Console.ReadKey()首先不会导致问题.