在多线程程序中使用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()
。
我发现这种行为非常神秘。这很容易解决,但我很感兴趣为什么会发生。
[编辑]
如果我在Thread.Sleep(1)
之前添加Console.ReadKey()
,它会按预期工作。当然,这不应该是必要的,因为Console.ReadKey()
应该永远等待。
所以它看起来可能是某种竞争条件?
更多信息:Servy发现(并且我已经重复)线Console.WriteLine("Entering the test() function.")
阻塞,直到任何键被按下。
构建配置
Visual Studio 2012,Windows 7 x64,四核,英语(英国)。
我已经尝试过.Net4,.Net4.5,x86,AnyCPU以及调试和发布的所有组合,但它们都不能在我的电脑上运行。但是发生了一件非常奇怪的事情。当我第一次尝试使用.Net4的AnyCPU版本时,它开始工作,但随后又停止了工作。看起来非常像只影响某些系统的竞争条件。
答案 0 :(得分:17)
这是竞争条件。以下是当第一个Console.WriteLine不存在时发生的事情:
当Console.WriteLine留在那里时它表现不同的原因是因为对Console.InitializeStdOutError的调用没有与Console.ReadKey并行发生。
所以简短的回答是:是的,你滥用控制台。您可以自己初始化控制台(通过解除引用Console.Out),或者在启动任务之后但在ReadKey之前等待事件,然后在第一次调用Console.WriteLine之后让Task发出事件信号。
答案 1 :(得分:3)
确认.NET 4.5中的内部错误。 例如,此处已报告:https://connect.microsoft.com/VisualStudio/feedback/details/778650/undocumented-locking-behaviour-in-system-console
这适用于.NET 3.5和.NET 4。
您可以使用简单的解决方法来初始化内部结构并避免阻塞。只需将其添加到beggining(来自@renestein):
Console.Error.WriteLine();
Console.WriteLine();
答案 2 :(得分:0)
这可能发生,因为它是多线程的。在您的异步任务有机会报告之前,您的主要线程正在继续并退出。当主线程退出时,所有子线程都被杀死。
如果您在ReadKey之前等待,该怎么办?它输出正确吗?
答案 3 :(得分:0)
根据我的评论,如果启用了“QuickEdit”(Windows 控制台功能,而不是 .NET),就会发生这种情况。在这种情况下,单击控制台窗口将阻止写入。
在窗口外单击、按 Esc 键或禁用 QuickEdit 可解决此问题:
相关:How and why does QuickEdit mode in Command Prompt freeze applications?