我的问题是:为什么会发生这种情况?这是一个bug,还是因为我滥用控制台?
(注意,控制台应该是线程安全的,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(“输入test()函数”)的行被阻塞,直到按下任何键.
构建配置
Visual Studio 2012,Windows 7 x64,Quad Core,英语(英国).
我已经尝试过所有的.Net4,.Net4.5,x86,Anycpu的组合,并且调试和释放,并且它们都不在我的电脑上工作.但是真的很奇怪的事情发生了.当我第一次尝试使用.Net4的Anycpu版本时,它开始工作,但是它再次停止工作.似乎非常喜欢竞争条件,只影响一些系统.
解决方法
>任务创建,但不运行
> Console.ReadKey执行,对Console.InternalSyncObject执行锁定,并阻止等待输入
> Task的Console.WriteLine调用Console.Out,调用Console.InitializeStdOutError进行首次初始化以设置控制台流
> Console.InitializeStdOutError尝试锁定Console.InternalSyncObject,但Console.ReadKey已经拥有它,所以它阻止
>用户按下一个键和Console.ReadKey返回,释放锁定
>对Console.WriteLine的调用被解除阻塞并完成执行
>进程退出,因为ReadKey调用后Main中没有任何内容
>任务中剩下的代码没有机会运行
当Console.WriteLine留在那里时,它的行为不同,原因是调用Console.InitializeStdOutError并不是与Console.ReadKey并行发生的.
所以简短的答案是:是的,你正在滥用控制台.您可以自己初始化控制台(通过取消引用Console.Out),或者在启动任务后,等待ReadKey之前的事件,然后在第一次调用Console.WriteLine后将Task发送给事件.