使用await with continueOnCapturedContext时,为什么TPL没有死锁:true?

时间:2014-07-18 01:40:19

标签: c# asynchronous task-parallel-library deadlock

这个问题与await vs Task.Wait - Deadlock?不同。这个问题涉及(据称)等待导致僵局的情况,并且。等等。这个问题恰恰相反。另外,问题和回答者在另一个问题上存在分歧,所以根本无法回答我的问题。

这会导致ASP.Net请求上下文出现死锁:

    protected void TestBtnClick(object sender, EventArgs e)
    {
        DoSomethingAsync()
            .Wait();
    }


    private async Task DoSomethingAsync()
    {
        await Task.Delay(2000)
                  .ConfigureAwait(continueOnCapturedContext: true);
    }

我的理解是第一个调用方法正在等待编组原始同步上下文,然后被调用的方法也等待编组原始上下文,从而导致死锁。

如果是这种情况,为什么以下内容也会造成死锁?

    protected async void TestBtnClickAsync(object sender, EventArgs e)
    {
        await DoSomethingAsync()
            // ****** DIFFERENCE IS HERE: ******
            .ConfigureAwait(continueOnCapturedContext: true);
    }


    private async Task DoSomethingAsync()
    {
        await Task.Delay(2000)
                  .ConfigureAwait(continueOnCapturedContext: true);
    }

请注意,两个异步调用都显式请求继续原始同步上下文。

2 个答案:

答案 0 :(得分:2)

因为在您的第一个代码块中,您明确地调用了Wait()。这会阻止线程的执行,因此永远不能在该线程上安排延续。线程永远不会返回到池中,它坐在那里等待信号继续执行,它永远不能接收,因为该信号将来自等待在等待线程上安排的延续。

在第二个块中,await关键字将线程返回到池中,以便稍后在该线程上可以再次调度该线程(从处理其他请求)。

答案 1 :(得分:1)

你可以在相同的上下文中等待很多等待的原因是因为他们让其他人在此期间使用它

想象一下,在线程上执行就像在其中一个中坚持一样#34;必须坚持说话"组。你的第一个例子就像是一个人向某人询问一个问题,然后在问题得到解答之前拒绝放弃。但是另一个人在得到棒之前无法回答!显然,这里会出现问题。

在你的第二个例子中,这个人向某人询问一个问题,要求在给出答案后给予回击,然后放弃棍子。一路上可能会有一些无关的喋喋不休,但至少这个问题会得到解答。好多了。

(请注意,继续捕获的上下文是默认设置,因此您不会通过明确要求更改任何内容。)