今夜、私は制約付き実行領域をいじって、より細かい部分の理解を深めました。以前にも時々使用したことがありますが、その場合は、ほとんどの場合、確立されたパターンに厳密に従っていました。とにかく、うまく説明できない奇妙なことに気づきました。
次のコードを検討してください。注: .NET 4.5 を対象とし、デバッガーをアタッチせずにリリース ビルドでテストしました。
public class Program
{
    public static void Main(string[] args)
    {
        bool toggle = false;
        bool didfinally = false;
        var thread = new Thread(
            () =>
            {
                Console.WriteLine("running");
                RuntimeHelpers.PrepareConstrainedRegions();
                try
                {
                    while (true) 
                    {
                      toggle = !toggle;
                    }
                }
                finally
                {
                    didfinally = true;
                }
            });
        thread.Start();
        Console.WriteLine("sleeping");
        Thread.Sleep(1000);
        Console.WriteLine("aborting");
        thread.Abort();
        Console.WriteLine("aborted");
        thread.Join();
        Console.WriteLine("joined");
        Console.WriteLine("didfinally=" + didfinally);
        Console.Read();
    }
}
このプログラムの出力はどうなると思いますか?
- didfinally=真
- didfinally=偽
推測する前に、ドキュメントを読んでください。以下に関連するセクションを含めます。
制約付き実行領域 (CER) は、信頼できるマネージド コードを作成するためのメカニズムの一部です。CER は、共通言語ランタイム (CLR) が帯域外例外をスローしないように制限されている領域を定義します。これにより、領域内のコードが完全に実行されなくなります。その領域内では、ユーザー コードは、帯域外例外のスローにつながるコードの実行を制限されます。PrepareConstrainedRegions メソッドは、try ブロックの直前に配置する必要があり、catch、finally、および fault ブロックを制約付き実行領域としてマークします。制約付き領域としてマークされると、コードは強力な信頼性コントラクトを持つ他のコードのみを呼び出す必要があり、コードが障害を処理する準備ができていない限り、準備されていないメソッドまたは信頼できないメソッドに割り当てたり、仮想呼び出しを行ったりすることはできません。CLR は、CER で実行されているコードのスレッド アボートを遅らせます。
と
信頼性の try/catch/finally は、アンマネージ バージョンと同じレベルの予測可能性を保証する例外処理メカニズムです。catch/finally ブロックは CER です。ブロック内のメソッドは事前の準備が必要であり、中断できないようにする必要があります。
私が今特に関心を持っているのは、スレッドのアボートを防ぐことです。Thread.Abort通常のバージョンと、CLR ホストが完全に中途半端になり、強制的に中止できるバージョンの2 種類があります。ブロックはすでにある程度finally保護されています。Thread.Abort次に、そのfinallyブロックをCERとして宣言すると、CLRホストの異常終了からの保護も強化されます...少なくともそれが理論だと思います。
したがって、私が知っていると思うことに基づいて、#1を推測しました。didfinally=True と表示されるはずです。ThreadAbortExceptionコードがまだブロック内にある間に が挿入され、 CER がなくてもtry、CLR によってfinallyブロックが期待どおりに実行されますか?
まあ、これは私が得た結果ではありません。まったく予想外の結果になりました。#1も#2も私には起こりませんでした。代わりに、私のプログラムは でハングしましたThread.Abort。これが私が観察するものです。
- 遅延スレッドが存在すると、ブロックPrepareConstrainedRegions内でアボートします。try
- が存在しないため、ブロックでPrepareConstrainedRegions使用できます。try
それで、百万ドルの質問はなぜですか?ドキュメントには、この動作についてはどこにも言及されていません。実際、私が読んでいるもののほとんどは、finally特にスレッドの異常終了を防ぐために、重要な割り込み不可能なコードをブロックに入れることを実際に示唆しています。
おそらく、ブロックに加えて、ブロック内PrepareConstrainedRegionsの通常のアボートを遅らせます。しかし、CLR ホストの中止は、CERのブロックでのみ遅延しますか? 誰かがこれについてもっと明確にすることができますか?tryfinallyfinally