我目前正在深入阅读C#(第3版),其中一个警告是使用带有task.wait的GUI线程是危险的,因为它可能导致死锁。但它不是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);
}
谢谢你
答案 0 :(得分:5)
我详细解释了这一点in a blog post。
会发生什么(默认情况下)await
将捕获当前的“上下文”并使用该上下文来恢复async
方法的执行。此“上下文”为SynchronizationContext.Current
,除非它是null
,在这种情况下为TaskScheduler.Current
。
在您的示例中,SynchronizationContext.Current
为null
,TaskScheduler.Current
为TaskScheduler.Default
,即线程池任务调度程序。因此,async
方法在线程池线程上恢复,并且没有死锁。线程池线程完成async
方法,完成Task
,允许主线程完成等待。
(在死锁的情况下,有一个SynchronizationContext
表示UI线程,因此async
方法尝试在UI线程上恢复,但是通过调用Wait
来阻止UI线程