興味深い問題:アプリケーションの安定性(堅牢性)を高める(パート3)-CERおよび他のフェイントのコード

持続可能なアプリケーションとCER( ここから )のトピックを続けて、制約実行領域で実行するために任意の(またはほぼ任意の)コードを準備する方法を検討します。



なぜこれが必要なのですか? CERの準備の過程で、スタックとプレジットの検査が行われることを思い出してください。 ただし、インターフェイスまたは仮想メソッドを介して呼び出しが行われた場合、スタックを検査することはできません。 したがって、このコード:
...     RuntimeHelper.PrepareConstrainedRegions();      try {}     finally {          obj.SomeVirtualMethod();     }
      
      



コンパイルしますが、実行時に必要なものを達成しません。



仮想メソッドを準備するには、RuntimeHelpersクラスの別の可能性-PrepareMethod()メソッドを使用する必要があります。
     ...    RuntimeHelpers.PrepareMethod(obj.GetType().GetMethod("SomeVirtualMethod").MethodHandle);    RuntimeHelpers.PrepareConstrainedRegions();     try {}    finally {         obj.SomeVirtualMethod();    }
      
      



これで、リージョンが準備され、正常に機能するようになります。

インターフェイスを介した呼び出しの場合、インターフェイスの背後に隠れている可能性のあるすべてのクラスのメソッドを準備する必要があることを既に理解していると思います。 悲しいが本当。

デリゲートの場合、手順は似ていますが、これを覚えておいてください-PrepareDelegateはリストの最初のデリゲートでのみ動作します-これはMulticastDelegateではリストの最初のデリゲートのみが処理されることを意味します-リストからすべてのデリゲートを手動で調べて準備する必要があります

イベントにのみデリゲートを使用し、CERからイベントをトリガーする場合、状況はいくらか単純化されます。以下のコードを使用すると、デリゲートを自動的に準備できます。
 public event EventHandler MyEvent {  add {    if (value == null) return;    RuntimeHelpers.PrepareDelegate(value);    lock(this) _myEvent += value;  }   remove { lock(this) _myEvent -= value; } }
      
      



大きな責任には大きな力が伴うことは明らかです。 また、非同期例外を制限およびスローすることなくコードを実行できることは大きな力です。 .netインフラストラクチャにより、開発者は、コードがCERの下で実行されるときにコードが負う責任を指定できます。 そして、System.Runtime.ConstrainedExecution.ReliabilityContractAttribute属性を使用してこれを行います。 この属性は、アセンブリレベルまたはクラスレベルとメソッドレベルの両方で適用でき、必要な詳細レベルを提供します。

この属性を適用しようとすると、有効な列挙から2つのプロパティ、CerとConsistencyGuaranteeを設定できることがわかります。 ConsistencyGuaranteeは、Cerで実行されたときに非同期例外でスコアリングされた場合にメソッドが引き起こす可能性のある「破壊」の責任を負います。 これは彼の広告がどのように見えるかです(翻訳する必要はないと思います):
 public enum Consistency { MayCorruptProcess = 0, MayCorruptAppDomain = 1, MayCorruptInstance = 2, WillNotCorruptState = 3 }
      
      



また、Cerは、メソッド呼び出しがどの程度成功するかについて責任を負います。 値を取ることができます
 { None = 0, MayFail = 1, Success = 2 }
      
      





これらのプロパティの多数の組み合わせにもかかわらず、CERの実行を開始するメソッドでは、3つの組み合わせのみが有効です。

-[ReliabilityContract(Consistency.MayCorruptInstance、Cer.MayFail)]-「私の小屋は端にあり、何も知りません」; オブジェクトのインスタンスに加えてエラーが発生した場合、何も影響を受けません。

-[ReliabilityContract(Consistency.WillNotCorruptState、Cer.MayFail)]-「クリーン」ドロップ:落ちても、作業を続行できます。

[ReliabilityContract(Consistency.WillNotCorruptState、Cer.Success)]-「メソッドは絶対に落ちません」

デフォルトでは、すべてのメソッドに[ReliabilityContract(Consistency.WillCorruptProcess、Cer.None)]属性があると見なされます。

これらの実行契約は、フレームワークホスティング環境によって解釈され、それに応じて問題に対応します。たとえば、致命的なことが既に発生している場合はドメインを事前に「ビート」し、プログラムが他の何かに損害を与えないようにします。



これが最後です。 acervは以前の投稿でStackOverflowについて尋ねました。 「-彼らは尋ねましたか?私たちは答えます!」 -.netフレームワークは、StackOverflowExceptionが発生した場合にスレッドがfinallyブロックを実行することを保証しません。 それにもかかわらず、きれいなコードではなく、すべて同じRuntimeHelperを使用するクリーンアップコードの実行を保証する簡単な機会はありません。 私はあまり説明しません:
 try {    RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup( TryMethod, CleanupMethod, this); } catch(SomeException exc) { ... } // Handle unexpected failure ... [MethodImpl(MethodImplOptions.NoInlining)] void TryMethod(object userdata) { ... } [MethodImpl(MethodImplOptions.NoInlining)] [ReliabilityContract(Cer.Success, Consistency.MayCorruptInstance)] void CleanupMethod(object userdata, bool fExceptionThrown) { ... }
      
      







ついに


面白かったと思います。

しかし、長い話題が際立っていました! :)また、SafeHandles、MemoryBarries、およびFailFastについても説明することがあります。 待って:)



All Articles