无法在async await上复制死锁

5

我预计以下代码会发生死锁:

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()并阻塞在taskTask.Wait()之后,主线程(当前上下文)被放置在等待状态,当DelayAndReturnAsync()完成时,它无法返回到方法并继续代码的其余部分。主线程将等待ProcessTaskAsync完成,而ProcessTaskAsync则在等待它(原始上下文)继续其余代码。因此会发生死锁。

如果我的理解有误,请告诉我。

我最初尝试复制死锁并测试使用ConfigureAwait(false)方法的解决方案,例如ProcessTaslAsync.ConfigureAwait(false)


1
你是想在控制台应用程序中测试这个吗? - shf301
1个回答

7
那种死锁只会发生在存在 SynchronizationContext 的情况下,而控制台应用程序默认情况下没有 SynchronizationContext。由于一开始就没有 SynchronizationContext,所以每个 await 都像隐式添加了 ConfigureAwait(false)
您可以在 UI 或 asp.net 应用程序中尝试它,或者更好地使用 Stephen Cleary 的 AsyncContext 添加一个 SynchronizationContext 来进行测试:

"AsyncContext 类型提供了执行异步操作的上下文。await 关键字需要返回到一个上下文;对于大多数程序来说,这是一个 UI 上下文,您不必担心它。ASP.NET 也提供了适当的上下文,您不必使用自己的。

但是,控制台应用程序和 Win32 服务没有合适的上下文,在这些情况下可以使用 AsyncContextAsyncContextThread。"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接