我目前正在深入阅读C#(第3版),给出的警告之一是将GUI线程与task.wait一起使用是危险的,因为它可能导致死锁。但这不是ThreadPool或Console的问题。我的问题是为什么运行 task.wait 的线程没有死锁,因此对于以下代码(取自书本),即使是控制台应用程序(backround)线程也不会进入捕获,因为它会死锁。
public static void Main(string[] args = null)
{
var source = new CancellationTokenSource();
var task = TestInt(source.Token);
source.CancelAfter(4000);
Console.WriteLine("Status {0}",task.Status);
try
{
task.Wait();
}
catch (AggregateException e)
{
Console.WriteLine("Caught {0}",e.InnerExceptions[0]);
}
Console.WriteLine("Final Status: {0}",task.Status);
Console.ReadKey();
}
public static async Task TestInt(CancellationToken token, double start = 1)
{
await Task.Delay(TimeSpan.FromSeconds(30), token);
}
谢谢
我在博客文章中详细解释了这一点。
发生的情况是(默认情况下)await
将捕获当前"上下文"并使用该上下文恢复async
方法的执行。这个"上下文"是SynchronizationContext.Current
的,除非它是null
的,在这种情况下它是TaskScheduler.Current
的。
在您的示例中,SynchronizationContext.Current
是null
,TaskScheduler.Current
是TaskScheduler.Default
,即线程池任务调度程序。因此,async
方法在线程池线程上恢复,并且没有死锁。线程池线程完成 async
方法,完成Task
,允许主线程完成其等待。
(在死锁情况下,有一个表示 UI 线程的SynchronizationContext
,因此 async
方法尝试在 UI 线程上恢复,但 UI 线程被调用 Wait
阻止)。