【发布时间】:2014-02-20 12:28:45
【问题描述】:
一个简单的问题。这是 WinForms 应用程序的一部分:
void Form1_Load(object sender, EventArgs e)
{
var task2 = Task.Factory.StartNew(() => MessageBox.Show("Task!"),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
Debug.WriteLine("Before Exit");
MessageBox.Show("Exit!");
}
谁能解释我为什么看到“任务!”首先,然后在我运行时“退出”?
当我看到“任务!”消息框,“退出前”已打印在调试输出中。
编辑:更简单,同样的效果:
void Form1_Load(object sender, EventArgs e)
{
SynchronizationContext.Current.Post((_) =>
MessageBox.Show("Task!"), null);
Debug.WriteLine("Before Exit");
MessageBox.Show("Exit!");
}
编辑:如果我用Form { Text = "Exit!" }.ShowDialog() 替换MessageBox.Show("Exit!"),我会看到“退出”,然后是“任务”,正如预期的那样。这是为什么呢?
【问题讨论】:
-
我认为这证明了 Win32
MessageBoxAPI(由 .NETMessageBox.Show包装)首先处理所有待处理的消息,然后显示其模式窗口。这与Form.ShowDialog的作品不同。 -
MessageBox.Show() 是 Application.DoEvents() 的另一个名称,你得到了所有神秘的重入行为,只有减去用户搞砸它的方式。将 async 关键字应用于只触发一次的事件,并且您创建了完美的风暴,将重入叠加在重入之上。这一切确实以一种扭曲的方式有意义,并且完全可以重现,只是很难推理。只有当您编写了所有代码时,才能理解递归。查看堆栈跟踪以了解它。
-
@HansPassant,如果我将
MessageBox.Show("Exit!")替换为Form { Text = "Exit!" }.ShowDialog(),我会看到“退出”,然后是“任务”,正如预期的那样。这是为什么呢? -
不同类型的递归,看调用栈。
-
@HansPassant,我删除了 async 和
Task.Delay,没有任何改变。我没有看到这里发生了任何递归,堆栈框架证实了这一点。
标签: c# .net asynchronous task-parallel-library synchronizationcontext