无法在异步等待上复制死锁
本文关键字:复制 死锁 等待 异步 | 更新日期: 2023-09-27 18:09:01
我预计以下代码会发生死锁:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task<int> ProcessTaskAsync()
{
var taskA = await DelayAndReturnAsync(3);
int num = taskA++;
return num;
}
static void Main(string[] arg)
{
var testTask = ProcessTaskAsync();
testTask.Wait();
Console.WriteLine("Done");
}
由于主线程(当前上下文)在调用ProcessTaskAsync()
后处于等待状态,并且在teskTask.Wait()
上被阻塞,因此当DelayAndReturnAsync()
完成时,它不能返回到该方法并继续其余的代码。主线程将等待ProcessTaskAsync
完成,而ProcessTaskAsync
正在等待它(原始上下文)继续执行其余的代码。因此出现了死锁。
ProcessTaskAsync
上使用ConfigureAwait(false)
方法的解决方案。例:
这种死锁只会发生在SynchronizationContext
存在的情况下,而CC_9在控制台应用程序中默认不存在。因为一开始没有SynchronizationContext
,所以好像每个await
都隐式地添加了ConfigureAwait(false)
。
您可以在UI或asp.net应用程序中尝试它,甚至更好地添加SynchronizationContext
到您的测试与Stephen Cleary的AsyncContext
:
"
AsyncContext
类型提供了执行异步操作的上下文。await关键字需要一个上下文来返回;对于大多数程序,这是一个UI context,你不必担心它。ASP。. NET还提供了适当的上下文,您不必使用自己的上下文。然而,控制台应用程序和Win32服务没有合适的上下文,
AsyncContext
或AsyncContextThread
可以在这些情况下使用。"