4

首先是一个向前的道歉:我无法将以下错误隔离到一个简单的控制台应用程序中。但是,在我比较简单的 ASP.NET Web Forms 应用程序中,下面的代码会导致当前线程无限期阻塞:

public class MyModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(System.Web.HttpApplication context)
    {
        context.BeginRequest += this.Context_BeginRequest;
    }

    private void Context_BeginRequest(object sender, EventArgs e)
    {
        Sleep().Wait();
        var x = 2; // This line is never hit.
    }

    private async Task Sleep()
    {
        await TaskEx.Run(() => System.Threading.Thread.Sleep(1000));
    }
}

任务状态保持为“WaitingForActivation”。有谁知道为什么会发生这种情况?

4

1 回答 1

5

编辑:斯蒂芬·克利里的评论更加清楚:

AspNetSynchronizationContext是最奇怪的实现。它将Post 视为同步而不是异步,并使用锁一次执行一个委托AspNetSynchronizationContext不需要封送回同一个线程(但确实需要获取锁);死锁Wait是因为继续等待锁(由事件处理程序中的线程持有)


我的猜测是,有一个SynchronizationContext强制继续在与事件处理程序相同的线程上运行。您的事件处理程序正在阻塞该线程,因此延续永远不会运行,这意味着事件处理程序永远不会unblock

不过,这只是一个猜测——这是我目前能想到的唯一有意义的事情。

尝试解除阻止的一种方法是将您的方法更改Sleep为:

private async Task Sleep()
{
    await TaskEx.Run(() => System.Threading.Thread.Sleep(1000))
                .ConfigureAwait(continueOnCapturedContext: false);
}

这将允许继续在不同的上下文中完成。

我很惊讶有这样一个同步上下文,请注意……我希望所有这些都发生在线程池上。可能BeginRequest稍微特殊对待。

于 2011-10-18T08:34:47.637 回答