gpt4 book ai didi

c# - 多线程 Console.ReadKey() 的奇怪行为

转载 作者:太空狗 更新时间:2023-10-29 17:35:01 27 4
gpt4 key购买 nike

在多线程程序中使用 Console.ReadKey() 时遇到了一个奇怪的问题。

我的问题是:为什么会这样?这是一个错误,还是因为我在滥用 Console?(请注意,控制台应该是线程安全的,according to the documentation。)

用代码来解释这个最简单:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("X"); // Also try with this line commented out.
Task.Factory.StartNew(test);
Console.ReadKey();
}

private static void test()
{
Console.WriteLine("Entering the test() function.");
Thread.Sleep(1000);
Console.WriteLine("Exiting the test() function.");
}
}
}

如果您运行它并且按下某个键,您认为它会打印出什么?

答案如你所料:

X
Entering the test() function.
Exiting the test() function.

现在注释掉 Console.WriteLine("X") 并再次运行它(不用按键)。我希望看到这个输出:

Entering the test() function.
Exiting the test() function.

相反,我什么都看不到。然后当我按下一个键时,它会说:

Entering the test() function.

...就是这样。程序退出(当然)并且它没有时间到达下一个 WriteLine()

我觉得这个行为很神秘。这很容易变通,但我很好奇为什么会这样。

[编辑]

如果我在 Console.ReadKey() 之前添加一个 Thread.Sleep(1),它会按预期工作。当然,这不是必需的,因为 Console.ReadKey() 应该永远等待。

所以看起来它可能是某种竞争条件?

更多信息:Servy 发现(我已经复制)Console.WriteLine("Entering the test() function.") 行一直阻塞,直到按下任何键。

构建配置

Visual Studio 2012,Windows 7 x64,四核,英语(英国)。

我已经尝试了 .Net4、.Net4.5、x86、AnyCPU 以及调试和发布的所有组合,但它们都无法在我的 PC 上运行。但是一件非常奇怪的事情发生了。当我第一次尝试 .Net4 的 AnyCPU 版本时它开始工作,但随后它再次停止工作。看起来非常像只影响某些系统的竞争条件。

最佳答案

这是一个竞争条件。这是第一个 Console.WriteLine 不存在时发生的情况:

  1. 任务已创建,但未运行
  2. Console.ReadKey 执行,锁定 Console.InternalSyncObject,并阻止等待输入
  3. 任务的 Console.WriteLine 调用 Console.Out,Console.Out 调用 Console.InitializeStdOutError 进行首次初始化以设置控制台流
  4. Console.InitializeStdOutError 尝试锁定 Console.InternalSyncObject,但 Console.ReadKey 已经拥有它,因此它会阻止
  5. 用户按下一个键,Console.ReadKey 返回,释放锁
  6. 对Console.WriteLine的调用解除阻塞并执行完毕
  7. 进程退出,因为调用 ReadKey 后 Main 中没有任何内容
  8. 任务中剩余的代码没有机会运行

当 Console.WriteLine 保留在那里时它表现不同的原因是因为对 Console.InitializeStdOutError 的调用没有与 Console.ReadKey 并行发生。

所以简短的回答是:是的,你在滥用控制台。您可以自己初始化控制台(通过取消引用 Console.Out),或者您可以在启动任务后但在 ReadKey 之前等待事件,然后让任务在第一次调用 Console.WriteLine 后发出事件信号。

关于c# - 多线程 Console.ReadKey() 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15143931/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com