首先是一个直截了当的道歉:我无法将以下bug隔离到一个简单的控制台应用程序中。但是,在我相对简单的ASP.NET Web窗体应用程序中,以下代码将导致当前线程无限期阻塞:

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”。有人知道为什么会这样吗?

最佳答案

编辑:斯蒂芬·克利里的评论透露了更多的信息:
AspNetSynchronizationContext是最奇怪的实现。它treats Post as synchronous rather than asynchronoususes a lock to execute its delegates one at a timeAspNetSynchronizationContext不需要封送回同一线程(但需要获取锁);在Wait上出现死锁是因为continuation正在等待锁(由事件处理程序中的线程持有)
我的猜测是有一个SynchronizationContext强制continuation在与事件处理程序相同的线程上运行。您的事件处理程序正在阻止该线程,因此continuation永远不会运行,这意味着事件处理程序永远不会取消阻止。
不过,这只是一个猜测——这是我目前唯一能想到的有意义的事情。
尝试解除阻止的一个选项是将Sleep方法更改为:

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

这将允许在不同的上下文中完成延续。
我很惊讶有这么一个同步上下文,请注意…我希望所有这些都发生在线程池中。可能BeginRequest被轻微特殊处理。

08-26 19:59