我目前正在深入阅读C#(第3版),其中一个警告是使用带有task.wait的GUI线程是危险的,因为它可能导致死锁.但它不是ThreadPool或Console的问题.我的问题是为什么运行task.wait的线程没有死锁,所以对于下面的代码(取自书),即使控制台应用程序(后台)线程也不会使它成为陷阱,因为它会死锁.
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);
}
Run Code Online (Sandbox Code Playgroud)
谢谢
我在博客文章中详细解释了这一点.
会发生什么(默认情况下)await将捕获当前的"上下文"并使用该上下文来恢复该async方法的执行.这种"背景" SynchronizationContext.Current除非是null,否则就是这样TaskScheduler.Current.
在您的示例中,SynchronizationContext.Currentis null和TaskScheduler.Currentis TaskScheduler.Default,即线程池任务调度程序.因此,该async方法在线程池线程上恢复,并且没有死锁.线程池线程完成该async方法,完成Task,允许主线程完成其等待.
(在死锁的情况下,有一个SynchronizationContext代表UI线程,因此该async方法尝试在UI线程上恢复,但UI线程被调用阻止Wait).