【问题标题】:Why does TPL not deadlock when using await with continueOnCapturedContext:true? [duplicate]为什么在使用 continueOnCapturedContext:true 的 await 时 TPL 不会死锁? [复制]
【发布时间】:2014-09-09 01:34:47
【问题描述】:

这个问题不同于await vs Task.Wait - Deadlock?。该问题涉及(据称) await 导致死锁而 .Wait 没有的情况。这个问题是反过来的。另外,提问者和回答者在另一个问题上存在分歧,所以它根本无法回答我的问题。

这会在 ASP.Net 请求的上下文中导致死锁:

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


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

我的理解是,第一个调用方法在等待marshall原来的同步上下文,然后被调用的方法也等待marshall原来的上下文,从而造成死锁。

如果是这样,为什么下面的也不会导致死锁?

    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);
    }

请注意,两个异步调用都明确请求在原始同步上下文中继续。

【问题讨论】:

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


    【解决方案1】:

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

    在您的第二个块中,await 关键字将线程返回到池中,以便稍后在该线程空闲时(处理其他请求)可以再次在该线程上安排继续。

    【讨论】:

      【解决方案2】:

      您可以在同一上下文中恢复大量等待的原因是,他们让其他人同时使用它

      想象一下,在线程上执行就像是那些“必须握着棍子才能说话”组中的棍子。你的第一个例子就像一个人问某人一个问题,然后在问题得到回答之前拒绝放弃。但是对方在拿到棍子之前是无法回答的!显然这里会有问题。

      在您的第二个示例中,该人向某人提出问题,在给出答案后要求将棍子还给,然后放弃棍子。一路上可能会有一些不相关的喋喋不休,但至少问题会得到回答。好多了。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-16
        • 1970-01-01
        • 1970-01-01
        • 2019-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多