为什么Windows服务中的异步阻塞会导致死锁?

时间:2017-01-17 10:26:17

标签: c# asynchronous async-await synchronizationcontext

我的代码中存在死锁问题。

我的代码如下所示:

public async Task DoStuff(input)
{
    await AsyncMethod();
    //internally calls an async method, and blocks for its return. sometimes couses deadlocks. 
    new MyService().DoMoreStuff();
}

MyService.DoMoreStuff 实施:

DoMoreStuff()
{
    return DoSuffAsyncMethod().Result;
}

此代码有时会让我在 DoSuffAsyncMethod 上遇到死锁,

MyService.DoMoreStuff 方法中。

但是,如果我将违规代码包装在任务中,则不再发生死锁

public async Task DoStuff(input)
{
    await AsyncMethod();
    await Task.Run(new MyService().DoMoreStuff());
}

更多信息

此代码在Windows服务的上下文中运行 因此,不涉及同步上下文。

我知道如何解决这个问题,但仍然不明白为什么代码会死锁。

有没有人可以建议解释混合同步异步代码的死锁,没有同步上下文?

修改

感谢您的评论。

我假设它死锁。

实际情况有点复杂,所以我简化了一点。

DoSuffAsyncMethod()中,我们正在调用远程异步服务,经过一段预定时间后 - 我们正在超时。

分析请求和接收服务,发现消息实际上是正确传输的。

因此,除非网络或网络框架相关问题,否则我们将陷入僵局。

我们假设它是死锁,因为一旦我们重新构建代码, DoSuffAsyncMethod 中的超时就会消失。

编辑2 代码

DoSuffAsyncMethod().Wait().Result

错了。

正确的代码是

DoSuffAsyncMethod().Result

问题是由于在调用堆栈中向下调用ConfigureAwait(true)。

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

await基本上意味着:“嘿thread继续做你的事情,当我准备好时,我会要求你继续我的工作”。线索就像:“是的,但是当我完成剩下的工作时,我会来找你”。然后你问线程Wait上一个任务,但它永远不会完成工作,因为完成它需要线程回到他身上(是的,等待它的线程......)< / p>

但是当你做的时候

await Task.Run(new MyService().DoMoreStuff());

await之后的线程可用于恢复之前等待的任务(DoMoreStuff()),因此他们都能够完成工作。

更多信息,可能会找到更好的解释here