4

まず、前向きな謝罪:次のバグを単純なコンソールアプリケーションに分離することはできません。ただし、私の比較的単純な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」のままです。なぜこれが起こるのか誰かが知っていますか?

4

1 に答える 1

5

編集:スティーブンクリアリーからのコメントはより多くの光を当てます:

AspNetSynchronizationContext最も奇妙な実装です。Postは非同期ではなく同期として扱われロックを使用してデリゲートを一度に1つずつ実行します。AspNetSynchronizationContext同じスレッドにマーシャリングする必要はありません(ただし、ロックを取得する必要があります)。デッドロックが発生するWaitのは、継続がロックを待機しているためです(イベントハンドラーのスレッドによって保持されます)。


私の推測ではSynchronizationContext、継続をイベントハンドラーと同じスレッドで実行するように強制しているがあります。イベントハンドラーがそのスレッドをブロックしているため、継続が実行されることはありません。つまり、イベントハンドラーがブロックを解除することはありません。

しかし、それは単なる推測です-現時点で私が考えることができるのはそれだけです。

これをブロック解除しようとする1つのオプションは、Sleepメソッドを次のように変更することです。

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

これにより、別のコンテキストで継続を完了することができます。

このような同期コンテキストがあることに驚いています。気をつけてください...これらすべてがスレッドプールで発生することを期待しています。おそらくBeginRequest少し特別に扱われます。

于 2011-10-18T08:34:47.637 に答える