11

我的一位同事发现我们的代码存在问题,花了一段时间才查明到底发生了什么,但这个简单的例子可以很好地证明这一点:

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

玩这个很明显,从主线程的任何地方写入控制台都将允许后台线程也写入控制台,但我们正在努力理解为什么会发生这种情况。谁能解释从主线程向控制台写入的内容是第一个片段没有实现的吗?

4

2 回答 2

5

实际上,第一种情况并没有失败。“Hello World”出现在应用程序结束之前。这是一个经典的Race Condition。在第一种情况下,Console.ReadKey()主线程击败了任务,在第二种情况下,任务获胜。不幸的是,我不能确切地告诉你为什么写空字符串会使任务获胜。

于 2013-01-17T17:04:22.660 回答
5

我怀疑发生了什么事。我观察到的:

  • 如果你在启动之前对控制台的输出做任何事情ReadKey,那很好。这包括获取Console.Out但不使用它
  • 如果您延迟通话以使Console.WriteLine通话在通话之前开始Console.ReadKey,那很好(并且您可以等待时拨打多个WriteLine电话 ReadKey

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

执行假设初始化的操作虽然很有趣 - 读取Console.Out“修复”问题,但读取Console.In不会。

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

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

于 2013-01-17T17:10:21.423 回答