无法在异步等待上复制死锁

本文关键字:复制 死锁 等待 异步 | 更新日期: 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服务没有合适的上下文,AsyncContextAsyncContextThread可以在这些情况下使用。"