![](/img/trans.png)
[英]How can blocking async calls cause a deadlock if async calls aren't necessarily executed on a different thread?
[英]Why this async method don't cause deadlock on a thread?
我需要解释为什么这段代码不会导致它正在运行的线程死锁(这是一个 WinForm 应用程序,这些发生在 button_Click 中):
Task FakeMainThread = Task.Run(async() => // fake main thread
{
async Task asyncMethod() // executed in FakeMainThread
{
await Task.Run(() => // 'await'ing in FakeMainThread
{
Thread.Sleep(5000);
MessageBox.Show("child Task finished");
return 3;
});
MessageBox.Show("asyncMethod finished");
}
asyncMethod().Wait(); // deadlock should appear in FakeMainThread
MessageBox.Show("FakeMainThread finished");
return 4;
});
asyncMethod().Wait();
应该阻止 fakeMainThread 任务的线程,而它正在等待另一个任务完成,并且由于在await
中也发生了等待,它不应该能够“等待”并且死锁应该出现在 fakeMainThread 上。 但它没有发生,我看到 bot MessageBox.Show("asyncMethod finished");
和MessageBox.Show("FakeMainThread finished");
消息。 注意:如果我把这个:
async Task asyncMethod()
{
await Task.Run(() =>
{
Thread.Sleep(5000);
MessageBox.Show("child Task finished");
return 3;
});
MessageBox.Show("asyncMethod finished");
}
asyncMethod().Wait(); // deadlock appears in Main Thread (UI)
MessageBox.Show("FakeMainThread finished");
在 directli 内的 main button1_click() 中,UI 上出现死锁。 谢谢!
由于SynchronizationContext
,您不会在第一个代码示例中遇到死锁。 这个上下文说明了 await 必须做什么来恢复你的代码。 当您开始一项新任务 ( Task.Run
) 时,您将获得默认上下文。 在button1_click
中,您可以从表单中获取上下文。
表单的上下文只允许执行一个线程(用于绘制/更新表单的线程)。
当您调用.Wait()
时,您会保持该线程“锁定”并等待任务完成。 这意味着线程没有被释放用于另一项工作,这是表单进入“无响应”state 的原因之一。
当您执行await [code]
并且该代码已完成时,它将要求同步上下文安排剩余的代码。
.Wait()
中的“循环”收到信号表明任务已完成并继续。 避免这种死锁是您经常收到使用ConfigureAwait(false)
的建议的主要原因,这告诉await
它应该用默认的同步上下文替换当前的同步上下文,从而允许您使用任何空闲线程。 您不想使用此功能(或说ConfigureAwait(true)
)的唯一原因是您是否需要更新表单(WPF 或 WinForms)上的某些内容,或者您需要 http 上下文(ASP.NET,而不是 ASP.NET 核心)。 这是因为只有一个线程可以访问您的表单或 http 上下文。 在这里,您的MessageBox.Show
不会出现异常,因为这是 forms 上下文的“外部”,并且不需要这个特殊的线程/同步上下文。
有关详细信息,请参阅https://devblogs.microsoft.com/dotnet/configureawait-faq/ 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.