信頼性に関するベスト プラクティスReliability Best Practices

以下の信頼性ルールは SQL Server を対象としたものですが、他のホスト ベースのサーバー アプリケーションにも当てはまります。The following reliability rules are oriented to SQL Server; however, they also apply to any host-based server application. SQL Server などのサーバーがリソースをリークせず、停止しないことが非常に重要です。It is extremely important that servers such as SQL Server not leak resources and not be brought down. ただし、オブジェクトの状態を変更するすべてのメソッドに対してバックアウト コードを記述することでは、それを実現できません。However, that cannot be done by writing back-out code for every method that alters an object’s state. 目標は、バックアウト コードによりすべての場所ですべてのエラーから復旧する 100% 信頼できるマネージド コードを記述することではありません。The goal is not to write 100 percent reliable managed code that will recover from any errors in every location with back-out code. それは、成功する可能性がほとんどない面倒な作業です。That would be a daunting task with little chance of success. 共通言語ランタイム (CLR) では、完全なマネージド コードを作成できるという十分に強力な保証は簡単には得られません。The common language runtime (CLR) cannot easily provide strong enough guarantees to managed code to make writing perfect code feasible. ASP.NET とは異なり、SQL Server で使用されているプロセスは 1 つだけであり、受け入れられないほど長い時間データベースを停止させない限りリサイクルできません。Note that unlike ASP.NET, SQL Server uses only one process that cannot be recycled without taking a database down for an unacceptably long time.

このように強力な保証がなく、単一プロセスで実行されている場合の信頼性は、必要なときにスレッドを終了するか、アプリケーション ドメインをリサイクルすること、および予防策を設けてハンドルやメモリなどのオペレーティング システム リソースがリークしないようにすることに基づきます。With these weaker guarantees and running in a single process, reliability is based on terminating threads or recycling application domains when necessary and taking precautions to ensure operating system resources such as handles or memory are not leaked. このような単純な信頼性の制約であっても、大きな信頼性の要件があります。Even with this simpler reliability constraint, there is still a significant reliability requirement:

  • オペレーティング システムのリソースがリークしないこと。Never leak operating system resources.

  • CLR に対するすべてのフォームにおいてすべてのマネージド ロックを識別すること。Identify all managed locks in all forms to the CLR.

  • アプリケーション間のドメイン共有状態を壊すことなく、AppDomain のリサイクルが円滑に機能すること。Never break cross-application domain shared state, allowing AppDomain recycling to function smoothly.

ThreadAbortExceptionStackOverflowExceptionOutOfMemoryException の各例外を処理するマネージド コードを記述することは理論的には可能ですが、アプリケーション全体でそのような堅牢なコードを記述することを開発者に期待するのは無謀です。Although it is theoretically possible to write managed code to handle ThreadAbortException, StackOverflowException, and OutOfMemoryException exceptions, expecting developers to write such robust code throughout an entire application is unreasonable. そのため、帯域外の例外では実行中のスレッドが終了します。また、終了したスレッドが共有の状態を編集していた場合は (これは、スレッドがロックを保持しているかどうかで判断できます)、AppDomain がアンロードされます。For that reason, out-of-band exceptions result in the executing thread being terminated; and if the terminated thread was editing shared state, which can be determined by whether the thread holds a lock, then the AppDomain is unloaded. 共有状態を編集しているメソッドが終了された場合、共有状態の更新に対する信頼性の高いバックアウト コードを記述することはできないため、状態が破損します。When a method that is editing shared state is terminated, the state will be corrupt because it is not possible to write reliable back-out code for updates to shared state.

.NET Framework バージョン 2.0 では、信頼性が必要なホストは SQL Server だけです。In the .NET Framework version 2.0, the only host that requires reliability is SQL Server. アセンブリが SQL Server で実行される場合は、データベースでの実行時には無効にされる特定の機能がある場合でも、そのアセンブリのすべての部分について信頼性の作業を行う必要があります。If your assembly will be run on SQL Server you should do the reliability work for every part of that assembly, even if there are specific features that are disabled when running in the database. これが必要になるのは、コード分析エンジンはアセンブリ レベルでコードを調べるため、無効にされるコードを区別できないためです。This is required because the code analysis engine examines code at the assembly level and cannot differentiate disabled code. SQL Server のプログラミングに関するもう 1 つの考慮事項は、SQL Server はすべての処理を 1 つのプロセスで実行し、メモリやオペレーティング システム ハンドルなどのすべてのリソースをクリーンアップするには AppDomain のリサイクルが使われるということです。Another SQL Server programming consideration is that SQL Server runs everything in one process, and AppDomain recycling is used for cleaning up all resources such as memory and operating system handles.

バックアウト コードでファイナライザー、デストラクター、または try/finally ブロックに依存することはできません。You cannot depend on finalizers or destructors or try/finally blocks for back-out code. これらは、中断されたり呼び出されない可能性があります。They might be interrupted or not called.

ThreadAbortExceptionStackOverflowExceptionOutOfMemoryException などの非同期例外が、予期しない場所 (すべてのマシン命令) でスローされる可能性があります。Asynchronous exceptions can be thrown in unexpected locations, possibly every machine instruction: ThreadAbortException, StackOverflowException, and OutOfMemoryException.

マネージド スレッドは必ずしも SQL 内の Win32 スレッドではありません。ファイバーである可能性があります。Managed threads are not necessarily Win32 threads in SQL; they might be fibers.

プロセス全体またはアプリケーション間のドメイン変更可能な共有状態は、安全に変更することが特に困難であり、可能な限り避ける必要があります。Process-wide or cross-application domain mutable shared state is extremely difficult to alter safely and should be avoided whenever possible.

メモリ不足の状況は SQL Server では珍しくありません。Out-of-memory conditions are not rare in SQL Server.

SQL Server でホストされているライブラリが共有状態を正しく更新しない場合、データベースを再起動しないかぎりコードを復旧できない可能性が高くなります。If libraries hosted in SQL Server do not correctly update their shared state, there is a high probability that the code will not recover until the database has been restarted. さらに、極端なケースでは、これにより SQL Server プロセスが失敗し、データベースが再起動する可能性があります。Additionally, in some extreme cases, it is possible this might cause the SQL Server process to fail, causing the database to reboot. データベースが再起動すると、Web サイトが停止したり、会社の運用に影響して、可用性が低下します。Rebooting the database can take down a Web site or affect company operations, hurting availability. メモリやハンドルなどのオペレーティング システムのリソースがゆっくりリークすると、最終的にサーバーでのハンドルの割り当てが失敗して復旧できなかったり、サーバーのパフォーマンスが徐々に悪化して顧客のアプリケーションの可用性が低下する可能性があります。A slow leak of operating system resources such as memory or handles may cause the server to eventually fail allocating handles with no possibility of recovery, or potentially the server may slowly degrade in performance and reduces a customer’s application availability. これらのシナリオを回避する必要があるのは明らかです。Clearly we want to avoid these scenarios.

ベスト プラクティスのルールBest Practice Rules

概要では、フレームワークの安定性と信頼性を向上させるために、サーバーで実行されるマネージド コードのコード レビューで把握する必要があることに注目しました。The introduction focused on what the code review for the managed code that runs in the server would have to catch to increase the stability and reliability of the framework. これらのチェックはすべて、一般的によいことであり、サーバーでは絶対に必要なことです。All these checks are good practice in general and an absolute must on the server.

SQL Server は、デッド ロックやリソースの制約が発生すると、スレッドを中止するか、AppDomain を破棄します。In the face of a dead lock or resource constraint, SQL Server will abort a thread or tear down an AppDomain. その場合は、制約された実行領域 (CER) 内のバックアウト コードのみが実行を保証されます。When this happens, only back-out code in a constrained execution region (CER) is guaranteed to be run.

SafeHandle を使ってリソースのリークを避けるUse SafeHandle to Avoid Resource Leaks

AppDomain がアンロードされる状況では、finally ブロックまたはファイナライザーが実行されることに依存できないので、IntPtrHandleRef、または同様のクラスではなく、SafeHandle クラスを使用して、オペレーティング システムのすべてのリソース アクセスを抽象化することが重要です。In the case of an AppDomain unload, you cannot depend on finally blocks or finalizers being executed, so it is important to abstract all operating system resource access through the SafeHandle class rather than IntPtr, HandleRef, or similar classes. これにより、AppDomain が破棄されても、CLR は使われたハンドルを追跡して閉じることができます。This allows the CLR to track and close the handles you use even in the AppDomain tear-down case. SafeHandle は、CLR が常に実行するクリティカル ファイナライザーを使います。SafeHandle will be using a critical finalizer which the CLR will always run.

オペレーティング システム ハンドルは、作成されてから解放されるまで、セーフ ハンドルに格納されます。The operating system handle is stored in the safe handle from the moment it is created until the moment it is released. ThreadAbortException が発生してハンドルをリークする可能性のある時間範囲はありません。There is no window during which a ThreadAbortException can occur to leak a handle. さらに、プラットフォームの呼び出しはハンドルを参照カウントするので、ハンドルの有効期間を詳細に追跡でき、Dispose と現在、ハンドルを使っているメソッドの間での競合状態によるセキュリティの問題を防ぐことができます。Additionally, platform invoke will reference-count the handle, which allows close tracking of the lifetime of the handle, preventing a security issue with a race condition between Dispose and a method that is currently using the handle.

現在、ファイナライザーを使ってオペレーティング システム ハンドルを単にクリーンアップしているほとんどのクラスは、ファイナライザーを使う必要がなくなります。Most classes that currently have a finalizer to simply clean up an operating system handle will not need the finalizer anymore. 代わりに、ファイナライザーは SafeHandle の派生クラスで呼び出されるようになります。Instead, the finalizer will be on the SafeHandle derived class.

SafeHandleIDisposable.Dispose の代わりに使う機能ではないことに注意してください。Note that SafeHandle is not a replacement for IDisposable.Dispose. 依然としてリソース競合の可能性はあり、オペレーティング システムのリソースを明示的に破棄するとパフォーマンス上の利点があります。There are still potential resource contention and performance advantages to explicitly dispose operating system resources. リソースの明示的な破棄を行っている finally ブロックが最後まで実行されない可能性があることだけは理解しておいてください。Just realize that finally blocks that do explicitly dispose of resources may not execute to completion.

SafeHandle を使うと、ハンドルを解放する処理 (オペレーティング システム ハンドル解放ルーチンに状態を渡す、ハンドルのセットをループで解放する、など) を実行する独自の ReleaseHandle メソッドを実装できます。SafeHandle allows you to implement your own ReleaseHandle method that performs the work to free the handle, such as passing state to an operating system handle freeing routine or freeing a set of handles in a loop. CLR はこのメソッドが実行されることを保証します。The CLR guarantees that this method is run. ReleaseHandle の実装の作成者には、あらゆる状況においてハンドルが解放されることを保証する責任があります。It is the responsibility of the author of the ReleaseHandle implementation to ensure that the handle is released in all circumstances. 解放できないとハンドルがリークされ、多くの場合、ハンドルに関連付けられているネイティブ リソースがリークすることになります。Failure to do so will cause the handle to be leaked, which often results in the leakage of native resources associated with the handle. したがって、ReleaseHandle の実装が呼び出し時に使用できない可能性があるリソースの割り当てを必要としないように、SafeHandle 派生クラスを構成することが不可欠です。Therefore it is critical to structure SafeHandle derived classes such that the ReleaseHandle implementation does not require the allocation of any resources that may not be available at invocation time. ReleaseHandle の実装内で失敗する可能性があるメソッドの呼び出しは、コードがそのようなエラーを処理し、コントラクトを完了してネイティブ ハンドルを解放できる場合に限り、許容されることに注意してください。Note that it is permissible to call methods that may fail within the implementation of ReleaseHandle provided that your code can handle such failures and complete the contract to release the native handle. デバッグのため、ReleaseHandle には、致命的なエラーが発生してリソースを解放できない場合に false に設定できる戻り値 Boolean があります。For debugging purposes, ReleaseHandle has a Boolean return value which may be set to false if a catastrophic error is encountered which prevents release of the resource. このようにすると、releaseHandleFailed MDA がアクティブ化されて (有効になっている場合)、問題を特定するのに役立ちます。Doing so will activate the releaseHandleFailed MDA, if enabled, to aid in identifying the problem. 他にはどのような影響もランタイムに与えません。ReleaseHandle は同じリソースに対して再び呼び出されることはなく、結果としてハンドルはリークされます。It does not affect the runtime in any other way; ReleaseHandle will not be called again for the same resource and consequently the handle will be leaked.

SafeHandle が適さない特定の状況があります。SafeHandle is not appropriate in certain contexts. ReleaseHandle メソッドは GC ファイナライザー スレッドで実行できるので、特定のスレッドで解放する必要があるすべてのハンドルは、SafeHandle にラップされていてはなりません。Since the ReleaseHandle method can be run on a GC finalizer thread, any handles that are required to be freed on a particular thread should not be wrapped in a SafeHandle.

ランタイム呼び出し可能ラッパー (RCW) は、コードを追加せずに CLR でクリーンアップできます。Runtime callable wrappers (RCWs) can be cleaned by the CLR without additional code. プラットフォーム呼び出しを使い、COM オブジェクトを IUnknown* または IntPtr として扱うコードの場合は、RCW を使うようにコードを書き直す必要があります。For code that uses platform invoke and treats a COM object as an IUnknown* or an IntPtr, the code should be rewritten to use an RCW. アンマネージド リリース メソッドがマネージド コードをコールバックする可能性があるため、このシナリオには SafeHandle は適していない場合があります。SafeHandle may not be adequate for this scenario due to the possibility of an unmanaged release method calling back into managed code.

コード分析ルールCode Analysis Rule

オペレーティング システムのリソースをカプセル化するには、SafeHandle を使います。Use SafeHandle to encapsulate operating system resources. HandleRef または IntPtr 型のフィールドは使わないでください。Do not use HandleRef or fields of type IntPtr.

オペレーティング システム リソースのリークを防ぐため、ファイナライザーが実行する必要がないようにするEnsure Finalizers Do Not Have to Run to Prevent Leaking Operating System Resources

ファイナライザーを慎重に検討し、ファイナライザーが実行しない場合でも重要なオペレーティング システムのリソースがリークされないことを確認します。Review your finalizers carefully to ensure that even if they do not run, a critical operating system resource is not leaked. アプリケーションが安定した状態で実行しているとき、または SQL Server などのサーバーがシャットダウンするときの、通常の AppDomain のアンロードとは異なり、AppDomain の突然のアンロードでは、オブジェクトの終了処理は行われません。Unlike a normal AppDomain unload when the application is executing in a steady state or when a server such as SQL Server shuts down, objects are not finalized during an abrupt AppDomain unload. アンロードが突然行われる場合は、アプリケーションの正しさは保証できませんが、リソースをリークしないことでサーバーの整合性を保持する必要があるため、リソースがリークされないことを確認します。Ensure resources are not leaked in the case of an abrupt unload, since an application's correctness cannot be guaranteed, but the integrity of the server must be maintained by not leaking resources. オペレーティング システムのリソースを解放するには、SafeHandle を使います。Use SafeHandle to free any operating system resources.

オペレーティング システム リソースのリークを防ぐため、finally 句が実行する必要がないようにするEnsure That finally Clauses Do Not Have to Run to Prevent Leaking Operating System Resources

finally 句が CER の外部で実行される保証はないので、ライブラリ開発者はアンマネージ リソースを解放するために finally ブロック内のコードに依存しないようにする必要があります。finally clauses are not guaranteed to run outside of CERs, requiring library developers to not rely on code within a finally block to free unmanaged resources. SafeHandle を使うのが推奨される解決策です。Using SafeHandle is the recommended solution.

コード分析ルールCode Analysis Rule

Finalize の代わりに、SafeHandle を使ってオペレーティング システムのリソースをクリーンアップします。Use SafeHandle for cleaning up operating system resources instead of Finalize. IntPtr を使わないでください。リソースをカプセル化するには SafeHandle を使います。Do not use IntPtr; use SafeHandle to encapsulate resources. finally 句を実行する必要がある場合は、CER 内に配置します。If the finally clause must run, place it in a CER.

すべてのロックは、既存のマネージド ロック コードを通過する必要があるAll Locks Should Go Through Existing Managed Locking Code

CLR は、スレッドの単なる中止ではなく、AppDomain のティアダウンが必要な場合を知るため、コードがロック状態であることを認識する必要があります。The CLR must know when code is in a lock so that it will know to tear down the AppDomain rather than just aborting the thread. スレッドの中止は、スレッドで使われているデータが不整合な状態のままになる可能性があるため、危険な場合があります。Aborting the thread could be dangerous as the data operated on by the thread could be left in an inconsistent state. したがって、AppDomain 全体をリサイクルする必要があります。Therefore, the entire AppDomain has to be recycled. ロックを識別できないと、デッドロックまたは不適切な結果になる可能性があります。The consequences of failing to identify a lock can be either deadlocks or incorrect results. ロック領域を識別するには、BeginCriticalRegion および EndCriticalRegion メソッドを使います。Use the methods BeginCriticalRegion and EndCriticalRegion to identify lock regions. これらは Thread クラスの静的メソッドであり、現在のスレッドにのみ適用され、あるスレッドのロック カウントを別のスレッドが編集するのを防ぐのに役立ちます。They are static methods on the Thread class that only apply to the current thread, helping to prevent one thread from editing another thread’s lock count.

これらのメソッドを使う lock ステートメントを使うだけでなく、この CLR 通知が組み込まれている Enter および Exit を使うこともお勧めします。Enter and Exit have this CLR notification built in, so their usage is recommended as well as the use of the lock Statement, which uses these methods.

スピン ロックや AutoResetEvent などの他のロック メカニズムは、これらのメソッドを呼び出して、クリティカルなセクションに入ったことを CLR に通知する必要があります。Other locking mechanisms such as spin locks and AutoResetEvent must call these methods to notify the CLR that a critical section is being entered. これらのメソッドはロックを取得しません。コードがクリティカル セクションで実行していて、スレッドを中止すると共有状態の一貫性がなくなることを、CLR に通知します。These methods do not take any locks; they inform the CLR that code is executing in a critical section and aborting the thread could leave shared state inconsistent. カスタム ReaderWriterLock クラスなどの独自のロックの種類を定義している場合は、これらのロック カウント メソッドを使います。If you have defined your own lock type, such as a custom ReaderWriterLock class, use these lock count methods.

コード分析ルールCode Analysis Rule

BeginCriticalRegion および EndCriticalRegion を使ってすべてのロックをマークして識別します。Mark and identify all locks using BeginCriticalRegion and EndCriticalRegion. ループでは CompareExchangeIncrement、および Decrement を使わないでください。Do not use CompareExchange, Increment, and Decrement in a loop. これらのメソッドの Win32 バリエーションのプラットフォーム呼び出しは行わないでください。Do not do a platform invoke of the Win32 variants of these methods. ループでは Sleep を使わないでください。Do not use Sleep in a loop. volatile フィールドを使わないでください。Do not use volatile fields.

クリーンアップ コードは catch の後ではなく finally ブロックまたは catch ブロック内に入れる必要があるCleanup Code Must Be in a finally or a catch Block, Not Following a catch

クリーンアップ コードは、catch ブロックの後ではなく、finally または catch ブロック自体の中に置く必要があります。Cleanup code should never follow a catch block; it should be in a finally or in the catch block itself. これは普通に推奨される方法です。This should be a normal good practice. finally ブロックは、例外がスローされたときと、try ブロックが正常に終了したときの両方で同じコードが実行されるため、一般に優先される方法です。A finally block is generally preferred because it runs the same code both when an exception is thrown and when the end of the try block is normally encountered. ThreadAbortException などの予期しない例外がスローされた場合は、クリーンアップ コードは実行されません。In the event of an unexpected exception being thrown, for example a ThreadAbortException, the cleanup code will not run. finally でクリーンアップするアンマネージ リソースをは、リークを防ぐため、できれば SafeHandle にラップする必要があります。Any unmanaged resources that you would clean up in a finally should ideally be wrapped in a SafeHandle to prevent leaks. C# の using キーワードを効果的に使って、ハンドルなどのオブジェクトを破棄できることに注意してください。Note the C# using keyword can be used effectively to dispose of objects, including handles.

AppDomain のリサイクルによってファイナライザー スレッドでリソースをクリーンアップできますが、それでもクリーンアップ コードを適切な場所に配置することが重要です。Although AppDomain recycling can clean up resources on the finalizer thread, it is still important to put cleanup code in the correct place. ロックを保持していないときにスレッドが非同期例外を受け取った場合、CLR は AppDomain をリサイクルしないでスレッド自体を終了しようとすることに注意してください。Note that if a thread receives an asynchronous exception without holding a lock, the CLR attempts to end the thread itself without having to recycle the AppDomain. リソースが早期にクリーンアップされるようにすると、リソースの可用性が高くなり、有効期間が適切に管理されるようになる利点があります。Ensuring that resources are cleaned up sooner rather than later helps by making more resources available, and by better managing the lifetime. エラー コード パスでファイルへのハンドルを明示的に閉じず、SafeHandle ファイナライザーがクリーンアップするのを待った場合、次にコードがそれを実行したときに、ファイナライザーがまだ実行していないと、まったく同じファイルへのアクセスが失敗する可能性があります。If you do not explicitly close a handle to a file in some error code path then wait for the SafeHandle finalizer to clean it up, the next time your code runs it may fail trying to access the exact same file if the finalizer has not already run. このため、確実にクリーンアップ コードが存在して正しく機能するようにすることは、絶対に必要なことではありませんが、障害からよりクリーンかつ迅速に復旧するのに役立ちます。For this reason, ensuring that cleanup code exists and works correctly will help recover from failures more cleanly and quickly, even though it is not strictly necessary.

コード分析ルールCode Analysis Rule

catch の後のクリーンアップ コードは、finally ブロック内に配置する必要があります。Cleanup code after catch needs to be in a finally block. dispose の呼び出しは finally ブロック内に置きます。Place calls to dispose in a finally block. catch ブロックは、スローまたは再スローで終了する必要があります。catch blocks should end in a throw or rethrow. 例外はありますが (多数の例外のいずれかを取得する可能性があるときにネットワーク接続を確立できるかどうかを検出するコードなど)、通常の状況で複数の例外をキャッチする必要があるコードでは、コードをテストしてそれが成功するかどうかを確認する必要があることを示すようにします。While there will be exceptions, such as code detecting whether a network connection can be established where you might get any of a large number of exceptions, any code that requires the catching of a number of exceptions under normal circumstances should give an indication that the code should be tested to see if it will succeed.

アプリケーション ドメイン間ではプロセス全体で変更可能な共有状態を使わないようにするか、または制約された実行領域を使うProcess-Wide Mutable Shared State Between Application Domains Should Be Eliminated or Use a Constrained Execution Region

概要で説明したように、アプリケーション ドメイン間でプロセス全体の共有状態を確実な方法で監視するマネージド コードを記述するのは非常に困難な場合があります。As described in the introduction, it can be very difficult to write managed code that monitors process-wide shared state across application domains in a reliable manner. プロセス全体の共有状態は、Win32 コード、CLR 内、またはリモート処理を使うマネージド コードにおいて、アプリケーション ドメイン間で共有される何らかの種類のデータ構造です。Process-wide shared state is any sort of data structure shared between application domains, either in Win32 code, inside the CLR, or in managed code using remoting. 変更可能な共有状態をマネージド コードで正確に記述するのは非常に困難であり、静的な共有は細心の注意を払うことによってのみ実現できる場合があります。Any mutable shared state is very difficult to correctly write in managed code, and any static shared state might be done only with great care. プロセス全体またはコンピューター全体の共有状態がある場合は、それを使わないで済む方法を探すか、制約された実行領域 (CER) を使って共有状態を保護するようにします。If you have process-wide or machine-wide shared state, find some way to eliminate it or protect the shared state using a constrained execution region (CER). 共有状態の識別と修正が行われていないライブラリでは、AppDomain のクリーンなアンロードを必要とする SQL Server などのホストがクラッシュする可能性があることに注意してください。Note that any library with shared state that is not identified and corrected could cause a host, such as SQL Server, that requires clean AppDomain unloading to crash.

コードが COM オブジェクトを使っている場合は、アプリケーション ドメイン間でその COM オブジェクトを共有しないでください。If code uses a COM object, avoid sharing that COM object between application domains.

プロセス全体またはアプリケーション ドメイン間ではロックが機能しないLocks Do Not Work Process-Wide or Between Application Domains.

以前は、Enter および lock ステートメントは、グローバルなプロセス ロックの作成に使われていました。In the past, Enter and the lock Statement have been used to create global process locks. たとえば、これは、非共有アセンブリからの Type インスタンスなどの AppDomain のアジャイル クラス、Thread オブジェクト、インターン処理された文字列、およびリモート処理を使ってアプリケーション ドメイン間で共有される文字列でのロック時に発生します。For example, this occurs when locking on AppDomain agile classes, such as Type instances from non-shared assemblies, Thread objects, interned strings, and some strings shared across application domains using remoting. これらのロックはプロセス全体ではなくなりました。These locks are no longer process-wide. プロセス全体にわたるアプリケーション間ドメイン ロックの存在を識別するには、ロック内のコードが、ディスク上のファイルやデータベースなどの、外部の永続リソースを使っているかどうかを確認します。To identify the presence of a process-wide interapplication domain lock, determine if the code within the lock uses any external, persisted resource such as a file on disk or possibly a database.

保護されたコードが外部リソースを使っている場合、そのコードが複数のアプリケーション ドメインで同時に実行することがあるため、AppDomain 内でロックを取得すると問題が発生する可能性があることに注意してください。Note that taking a lock within an AppDomain might cause problems if the protected code uses an external resource because that code may run simultaneously across multiple application domains. これは、1 つのログ ファイルへの書き込み、またはプロセス全体のソケットへのバインドで、問題になる場合があります。This can be a problem when writing to one log file or binding to a socket for the entire process. これらの変更は、名前付きの Mutex または Semaphore インスタンスを使う以外に、マネージド コードを使ってプロセスのグローバルなロックを取得する簡単な方法はないことを意味します。These changes mean there is no easy way, using managed code, to get a process-global lock, other than using a named Mutex or Semaphore instance. 2 つのアプリケーション ドメインで同時に実行しないコードを作成するか、Mutex または Semaphore クラスを使ってください。Create code that does not run in two application domains simultaneously, or use the Mutex or Semaphore classes. 既存のコードを変更できない場合は、この同期を実現するために Win32 名前付きミューテックスを使わないでください。なぜなら、ファイバー モードで実行するということは、同じオペレーティング システム スレッドでミューテックスを取得して解放することが保証されないことを意味します。If existing code cannot be changed, do not use a Win32 named mutex to achieve this synchronization because running in fiber mode means you cannot guarantee the same operating system thread will acquire and release a mutex. アンマネージド コードを使ってロックを同期するのではなく、マネージド Mutex クラス、または名前付きの ManualResetEventAutoResetEvent、または Semaphore を使って、CLR が認識する方法でコード ロックを同期する必要があります。You must use the managed Mutex class, or a named ManualResetEvent, AutoResetEvent, or a Semaphore to synchronize the code lock in a manner that the CLR is aware of instead of synchronizing the lock using unmanaged code.

lock(typeof(MyType)) を使わないAvoid lock(typeof(MyType))

すべてのアプリケーション ドメイン間でコードのただ 1 つのコピーが共有される共有アセンブリのプライベートおよびパブリックの Type オブジェクトでも、問題が発生します。Private and public Type objects in shared assemblies with only one copy of the code shared across all application domains also present problems. 共有アセンブリの場合、プロセスごとに Type のインスタンスが 1 つだけ存在し、これは複数のアプリケーション ドメインがまったく同じ Type インスタンスを共有することを意味します。For shared assemblies, there is only one instance of a Type per process, meaning that multiple application domains share the exact same Type instance. Type のインスタンスでロックを取得すると、その AppDomain だけでなく、プロセス全体に影響するロックが取得されます。Taking a lock on a Type instance takes a lock that affects the entire process, not just the AppDomain. ある AppDomainType オブジェクトでロックを取得した後、そのスレッドが突然中止されると、ロックは解放されません。If one AppDomain takes a lock on a Type object then that thread gets abruptly aborted, it will not release the lock. その後、このロックにより、他のアプリケーション ドメインでデッドロックが発生する可能性があります。This lock then may cause other application domains to deadlock.

静的メソッドでロックを取得するよい方法は、静的な内部同期オブジェクトをコードに追加することです。A good way to take locks in static methods involves adding a static internal synchronization object to the code. これは、クラス コンストラクターが存在する場合はそれで初期化できますが、存在しない場合は次のようにして初期化できます。This could be initialized in the class constructor if one is present, but if not it can be initialized like this:

private static Object s_InternalSyncObject;
private static Object InternalSyncObject
{
    get
    {
        if (s_InternalSyncObject == null)
        {
            Object o = new Object();
            Interlocked.CompareExchange(
                ref s_InternalSyncObject, o, null);
        }
        return s_InternalSyncObject;
    }
}

その後、ロックを取得するときは、InternalSyncObject プロパティを使ってロックするオブジェクトを取得します。Then when taking a lock, use the InternalSyncObject property to obtain an object to lock on. クラス コンストラクターで内部同期オブジェクトを初期化した場合は、プロパティを使う必要はありません。You do not need to use the property if you have initialized the internal synchronization object in your class constructor. 二重チェックを行うロック初期化コードの例を次に示します。The double checking lock initialization code should look like this example:

public static MyClass SingletonProperty
{
    get
    {
        if (s_SingletonProperty == null)
        {
            lock(InternalSyncObject)
            {
                // Do not use lock(typeof(MyClass))
                if (s_SingletonProperty == null)
                {
                    MyClass tmp = new MyClass(…);
                    // Do all initialization before publishing
                    s_SingletonProperty = tmp;
                }
            }
        }
        return s_SingletonProperty;
    }
}

Lock(this) に関する注意事項A Note About Lock(this)

一般に、パブリックにアクセスできる個々のオブジェクトでロックを取得することは認められます。It is generally acceptable to take a lock on an individual object that is publicly accessible. しかし、オブジェクトがサブシステム全体のデッドロックを引き起こす可能性のあるシングルトン オブジェクトである場合は、前述のデザイン パターンの使用も検討する必要があります。However, if the object is a singleton object that might cause an entire subsystem to deadlock, consider using the above design pattern as well. たとえば、1 つの SecurityManager オブジェクトでのロックにより、AppDomain 内でデッドロックが発生し、AppDomain 全体が使用できなくなる可能性があります。For example, a lock on the one SecurityManager object could cause a deadlock within the AppDomain making the entire AppDomain unusable. この種のパブリックにアクセスできるオブジェクトではロックを取得しないことをお勧めします。It is good practice to not take a lock on a publicly accessible object of this type. ただし、個別のコレクションまたは配列でのロックの場合は、一般に問題になりません。However a lock on an individual collection or array should generally not present a problem.

コード分析ルールCode Analysis Rule

アプリケーション ドメイン間で使われる可能性がある型では、ロックを取得しないでください。または、ID を強く意識しないでください。Do not take locks on types that might be used across application domains or do not have a strong sense of identity. TypeMethodInfoPropertyInfoStringValueTypeThread、または MarshalByRefObject から派生するすべてのオブジェクトでは、Enter を呼び出さないでください。Do not call Enter on a Type, MethodInfo, PropertyInfo, String, ValueType, Thread, or any object that derives from MarshalByRefObject.

GC.KeepAlive の呼び出しを削除するRemove GC.KeepAlive Calls

非常に多くの既存のコードが、使うべき時に KeepAlive を使っていないか、または適切ではないときにそれを使っています。A significant amount of existing code either does not use KeepAlive when it should or uses it when it is not appropriate. SafeHandle に変換した後、ファイナライザーを使わずに、SafeHandle を使ってオペレーティング システム ハンドルの終了処理を行っている場合は、クラスで KeepAlive を呼び出す必要はありません。After converting to SafeHandle, classes do not need to call KeepAlive, assuming they do not have a finalizer but rely on SafeHandle to finalize the operating system handles. KeepAlive の呼び出しを残しておくことによるパフォーマンス コストはほんのわずかかもしれませんが、KeepAlive の呼び出しが、もう存在していないかもしれない有効期間の問題を解決するために必要または十分なものであると意識することは、コードの保守を困難にします。While the performance cost of retaining a call to KeepAlive may be negligible, the perception that a call to KeepAlive is either necessary or sufficient to solve a lifetime issue that may no longer exist makes the code more difficult to maintain. ただし、COM 相互運用機能の CLR 呼び出し可能ラッパー (RCW) を使うコードでは、KeepAlive がまだ必要です。However, when using the COM interop CLR callable wrappers (RCWs), KeepAlive is still required by code.

コード分析ルールCode Analysis Rule

KeepAlive を削除します。Remove KeepAlive.

ホスト保護属性を使うUse the Host Protection Attribute

HostProtectionAttribute (HPA) を使うと、宣言型のセキュリティ アクションを使ってホストの保護要件を決定でき、ホストは完全に信頼されたコードが特定のホストに対して適切ではない特定のメソッド (SQL Server に対する ExitShow など) を呼び出すのを防ぐことができます。The HostProtectionAttribute (HPA) provides the use of declarative security actions to determine host protection requirements, allowing the host to prevent even fully trusted code from calling certain methods which are inappropriate for the given host, such as Exit or Show for SQL Server.

HPA は、共通言語ランタイムをホストし、ホスト保護を実装している SQL Server などのアンマネージ アプリケーションにのみ影響します。The HPA affects only unmanaged applications that host the common language runtime and implement host protection, such as SQL Server. HPA を適用すると、セキュリティ アクションはクラスまたはメソッドが公開するホスト リソースに基づいてリンク確認要求を作成します。When applied, the security action results in the creation of a link demand based on the host resources the class or method exposes. コードがホスト保護されていないクライアント アプリケーションまたはサーバーで実行される場合、この属性は "消滅" します。つまり、検出されないため適用されません。If the code is run in a client application or on a server that is not host-protected, the attribute "evaporates"; it is not detected and therefore not applied.

重要

この属性の目的は、セキュリティ動作ではなく、ホスト固有のプログラミング モデルのガイドラインを強制することです。The purpose of this attribute is to enforce host-specific programming model guidelines, not security behavior. リンク確認要求はプログラミング モデルの要件への準拠を確認するために使われますが、HostProtectionAttribute はセキュリティ アクセス許可ではありません。Although a link demand is used to check for conformance to programming model requirements, the HostProtectionAttribute is not a security permission.

ホストにプログラミング モデルの要件がない場合、リンク確認要求は発生しません。If the host does not have programming model requirements, the link demands do not occur.

この属性は次のものを識別します。This attribute identifies the following:

  • ホスト プログラミング モデルには適合しないが、それ以外の問題はないメソッドまたはクラス。Methods or classes that do not fit the host programming model, but are otherwise benign.

  • ホスト プログラミング モデルに適合せず、サーバーが管理するユーザー コードが不安定になる可能性があるメソッドまたはクラス。Methods or classes that do not fit the host programming model and could lead to destabilizing server-managed user code.

  • ホスト プログラミング モデルに適合せず、サーバー プロセス自体が不安定になる可能性があるメソッドまたはクラス。Methods or classes that do not fit the host programming model and could lead to a destabilization of the server process itself.

注意

ホストで保護された環境で実行する可能性のあるアプリケーションによって呼び出されるクラス ライブラリを作成する場合は、HostProtectionResource リソース カテゴリを公開するメンバーにこの属性を適用する必要があります。If you are creating a class library that is to be called by applications that may execute in a host protected environment, you should apply this attribute to members that expose HostProtectionResource resource categories. この属性を持つ .NET Framework クラス ライブラリのメンバーについては、直前の呼び出し元だけがチェックされます。The .NET Framework class library members with this attribute cause only the immediate caller to be checked. カスタムのライブラリ メンバーについても、同じように直前の呼び出し元がチェックされるようにする必要があります。Your library member must also cause a check of its immediate caller in the same manner.

HPA の詳細については、「HostProtectionAttribute」を参照してください。Please find more information on HPA in HostProtectionAttribute.

コード分析ルールCode Analysis Rule

SQL Server の場合、同期またはスレッド化を導入するために使われるすべてのメソッドを、HPA で識別する必要があります。For SQL Server, all methods used to introduce synchronization or threading must identified with the HPA. これには、状態を共有するメソッド、同期されるメソッド、または外部プロセスを管理するメソッドが含まれます。This includes methods that share state, are synchronized, or manage external processes. SQL Server に影響を与える HostProtectionResource の値は、SharedStateSynchronization、および ExternalProcessMgmt です。The HostProtectionResource values that impact SQL Server are SharedState, Synchronization, and ExternalProcessMgmt. ただし、SQL に影響を与えるリソースを使うものだけでなく、いずれかの HostProtectionResource を公開するすべてのメソッドを HPA によって識別する必要があります。However, any method that exposes any HostProtectionResource should be identified by a HPA, not just those using resources affecting SQL.

アンマネージ コードで無期限にブロックしないDo Not Block Indefinitely in Unmanaged Code

マネージド コード内ではなくアンマネージド コード内でブロックすると、CLR がスレッドを中止できないため、サービス拒否攻撃を受ける可能性があります。Blocking in unmanaged code instead of in managed code can cause a denial of service attack because the CLR is not able to abort the thread. ブロックされたスレッドは、少なくとも一部の非常に安全でない操作を実行せずに、CLR が AppDomain をアンロードするのを妨げます。A blocked thread prevents the CLR from unloading the AppDomain, at least without doing some extremely unsafe operations. Windows を使用したブロックの同期プリミティブでは、許容できないものの明白な例です。Blocking using a Windows synchronization primitive is a clear example of something we cannot allow. 呼び出しでブロックReadFileソケットで避ける必要があります可能であれば、理想的には、Windows API はこのような操作がタイムアウトする機構を提供します。Blocking in a call to ReadFile on a socket should be avoided if possible — ideally the Windows API should provide a mechanism for an operation like this to time out.

ネイティブを呼び出すメソッドでは、合理的な有限のタイムアウトで Win32 呼び出しを使うのが理想的です。Any method that calls into native should ideally use a Win32 call with a reasonable, finite timeout. ユーザーがタイムアウトを指定できる場合は、何らかの特定のセキュリティ アクセス許可なしでは、ユーザーが無限のタイムアウトを指定できないようにする必要があります。If the user is allowed to specify the timeout, the user should not be allowed to specify an infinite timeout without some specific security permission. ガイドラインとしては、メソッドが 10 秒以上ブロックする場合は、タイムアウトをサポートするバージョンを使うか、CLR のサポートを追加する必要があります。As a guideline, if a method will block for more than ~10 seconds, you need to be using a version that supports timeouts or you need additional CLR support.

問題のある Api のいくつかの例を示します。Here are some examples of problematic APIs. パイプ (匿名と名前付きのどちらも) はタイムアウトを指定して作成できます。ただし、コードでは、NMPWAIT_WAIT_FOREVER を指定して CreateNamedPipeWaitNamedPipe を呼び出さないようにする必要があります。Pipes (both anonymous and named) can be created with a timeout; however, code must ensure it never calls CreateNamedPipe nor WaitNamedPipe with NMPWAIT_WAIT_FOREVER. さらに、タイムアウトを指定した場合でも、予期しないブロックが発生する可能性があります。Additionally, there can be unexpected blocking even if a timeout is specified. 匿名パイプで WriteFile を呼び出すと、すべてのバイトが書き込まれるまでブロックします。つまり、バッファーに読み取られていないデータがある場合、リーダーがパイプのバッファー内の領域を解放するまで、WriteFile の呼び出しをブロックします。Calling WriteFile on an anonymous pipe will block until all bytes are written, meaning if the buffer has unread data in it, the WriteFile call will block until the reader has freed up space in the pipe’s buffer. ソケットでは、タイムアウト メカニズムを優先する API を常に使う必要があります。Sockets should always use some API that honors a timeout mechanism.

コード分析ルールCode Analysis Rule

アンマネージ コードでのタイムアウトのないブロックは、サービス拒否攻撃です。Blocking without a timeout in unmanaged code is a denial of service attack. WaitForSingleObjectWaitForSingleObjectExWaitForMultipleObjectsMsgWaitForMultipleObjects、および MsgWaitForMultipleObjectsEx のプラットフォーム呼び出しは実行しないでください。Do not perform platform invoke calls to WaitForSingleObject, WaitForSingleObjectEx, WaitForMultipleObjects, MsgWaitForMultipleObjects, and MsgWaitForMultipleObjectsEx. NMPWAIT_WAIT_FOREVER は使わないでください。Do not use NMPWAIT_WAIT_FOREVER.

STA に依存する機能を識別するIdentify Any STA-Dependent Features.

COM シングルスレッド アパートメント (STA) を使用するコードを明らかにします。Identify any code that uses COM single-threaded apartments (STAs). SQL Server プロセスでは STA は無効になります。STAs are disabled in the SQL Server process. パフォーマンス カウンターやクリップボードなどの CoInitialize に依存する機能は、SQL Server 内では無効にする必要があります。Features that depend on CoInitialize, such as performance counters or the clipboard, must be disabled within SQL Server.

ファイナライザーに同期の問題がないことを確認するEnsure Finalizers Are Free of Synchronization Problems

.NET Framework の将来のバージョンでは、複数のファイナライザー スレッドが存在する可能性があります。つまり、同じ型の異なるインスタンスのファイナライザーが同時に実行します。Multiple finalizer threads might exist in future versions of the .NET Framework, meaning the finalizers for different instances of the same type run simultaneously. これらは、完全にスレッド セーフである必要はありません。ガベージ コレクターが、ただ 1 つのスレッドで特定のオブジェクト インスタンスのファイナライザーが実行されることを保証します。They do not have to be completely thread safe; the garbage collector guarantees that only one thread will run the finalizer for a given object instance. ただし、複数の異なるオブジェクト インスタンスで同時に実行するときの競合状態やデッドロックを回避するように、ファイナライザーをコーディングする必要があります。However, the finalizers must be coded to avoid race conditions and deadlocks when running simultaneously on multiple different object instances. ログ ファイルへの書き込みなどの外部状態をファイナライザーで使う場合は、スレッド処理の問題に対処する必要があります。When using any external state, such as writing to a log file, in a finalizer, threading issues must be handled. 終了処理に依存してスレッド セーフを提供しないでください。Do not rely on finalization to provide thread safety. マネージドまたはネイティブのスレッド ローカル記憶域を使って、ファイナライザー スレッドに状態を保存しないでください。Do not use thread local storage, managed or native, to store state on the finalizer thread.

コード分析ルールCode Analysis Rule

ファイナライザーには同期の問題が存在していない必要があります。Finalizers must be free of synchronization problems. 静的な変更可能状態をファイナライザーで使用しないでください。Do not use a static mutable state in a finalizer.

可能な限りアンマネージ メモリを避けるAvoid Unmanaged Memory If Possible

オペレーティング システム ハンドルと同じように、アンマネージ メモリはリークする可能性があります。Unmanaged memory can be leaked, just like an operating system handle. 可能であれば、stackalloc を使ってスタック上のメモリを使うか、fixed ステートメント や byte[] を使う GCHandle などの固定されたマネージド オブジェクトを使うようにします。If possible, try to use memory on the stack using stackalloc or a pinned managed object such as the fixed Statement or a GCHandle using a byte[]. 最終的には GC がこれらをクリーンアップします。The GC eventually cleans these up. ただし、アンマネージ メモリを割り当てる必要がある場合は、SafeHandle から派生するクラスを使ってメモリの割り当てをラップすることを考えます。However, if you must allocate unmanaged memory, consider using a class that derives from SafeHandle to wrap the memory allocation.

SafeHandle が適切ではないケースが少なくとも 1 つあることに注意してください。Note that there is at least one case where SafeHandle is not adequate. メモリの割り当てや解放を行う COM メソッド呼び出しでは、1 つの DLL が CoTaskMemAlloc を使ってメモリを割り当てた後、別の DLL が CoTaskMemFree でそのメモリを解放するのが一般的です。For COM method calls that allocate or free memory, it is common for one DLL to allocate memory via CoTaskMemAlloc then another DLL frees that memory with CoTaskMemFree. これらの場所で SafeHandle を使うのは、他の DLL がメモリの有効期間を制御できるようにする代わりに、アンマネージ メモリの有効期間を SafeHandle の有効期間に結び付けようとするため不適切です。Using SafeHandle in these places would be inappropriate since it will attempt to tie the lifetime of the unmanaged memory to the lifetime of the SafeHandle instead of allowing the other DLL control the lifetime of the memory.

catch(Exception) のすべての使用を確認するReview All Uses of Catch(Exception)

1 つの特定の例外ではなくすべての例外をキャッチする catch ブロックは、非同期例外もキャッチするようになります。Catch blocks that catch all exceptions instead of one specific exception will now catch the asynchronous exceptions as well. すべての catch(Exception) ブロックを調べて、スキップされる可能性のある重要ではないリソース解放やバックアウト コード、および ThreadAbortExceptionStackOverflowExceptionOutOfMemoryException の処理に関する catch ブロック自体の内部での不適切な可能性のある動作を探します。Examine every catch(Exception) block, looking for no important resource releasing or backout code that might be skipped, as well as potentially incorrect behavior within the catch block itself for handling a ThreadAbortException, StackOverflowException, or OutOfMemoryException. このコードでは、特定の例外だけを認識できる、または例外が発生したときは常に厳密に特定の 1 つの理由で失敗するということが、ログに記録されたり、想定されたりしている可能性があることに注意してください。Note that it is possible this code might be logging or making some assumptions that it may only see certain exceptions, or that whenever an exception happens it failed for exactly one particular reason. これらの想定は、ThreadAbortException を含むように更新することが必要な場合があります。These assumptions may need to be updated to include ThreadAbortException.

すべての例外をキャッチするようになっているすべての場所を、スローされると予想される特定の種類の例外だけをキャッチするように変更することを検討してください (文字列書式設定メソッドからの FormatException など)。Consider changing all places that catch all exceptions to catching a specific type of exception that you expect will be thrown, such as a FormatException from string formatting methods. このようにすると、catch ブロックが予期しない例外で実行されることがなくなり、予期しない例外をキャッチすることでコードのバグが非表示にされなくなります。This prevents the catch block from running on unexpected exceptions and will help ensure the code does not hide bugs by catching unexpected exceptions. 一般的なルールとして、ライブラリ コードでは例外を処理しないでください (例外をキャッチする必要があるコードが、呼び出しているコード内の設計上の欠陥を示す可能性があります)。As a general rule never handle an exception in library code (code that requires you to catch an exception may indicate a design flaw in the code you are calling). 場合によっては、例外をキャッチし、異なる例外の種類をスローすることで、より多くのデータを提供できることがあります。In some cases you may want to catch an exception and throw a different exception type to provide more data. このような場合は入れ子になった例外を使い、エラーの実際の原因を新しい例外の InnerException プロパティに格納します。Use nested exceptions in this case, storing the real cause of the failure in the InnerException property of the new exception.

コード分析ルールCode Analysis Rule

すべてのオブジェクトまたはすべての例外をキャッチしているマネージド コード内のすべての catch ブロックを確認します。Review all catch blocks in managed code that catch all objects or catch all exceptions. C#、つまり、両方のフラグを設定catch{}とcatch(Exception){}します。In C#, this means flagging both catch {} and catch(Exception) {}. 例外の種類を非常に限定的にすることを考えます。または、コードを調べて、予期しない例外の種類をキャッチした場合に不適切に動作しないことを確認します。Consider making the exception type very specific, or review the code to ensure it does not act in a bad way if it catches an unexpected exception type.

マネージド スレッドが Win32 スレッド (ファイバー) であると想定してはならないDo Not Assume a Managed Thread Is a Win32 Thread – It Is a Fiber

マネージド スレッド ローカル記憶域は動作しますが、アンマネージド スレッド ローカル記憶域を使うこと、またはコードが現在のオペレーティング システム スレッドで再び実行されると想定することはできません。Using managed thread local storage does work, but you may not use unmanaged thread local storage or assume the code will run on the current operating system thread again. スレッドのロケールなどの設定を変更しないでください。Do not change settings like the thread’s locale. プラットフォーム呼び出しでは InitializeCriticalSection または CreateMutex を呼び出さないでください。これらでは、ロックを開始したオペレーティング システム スレッドがロックを終了する必要があります。Do not call InitializeCriticalSection or CreateMutex via platform invoke because they require the operating system thread that enters a lock also exit the lock. ファイバーを使うとこれは該当しないので、Win32 のクリティカル セクションおよびミューテックスを SQL で直接使うことはできません。Since this will not be the case when using fibers, Win32 critical sections and mutexes cannot be used in SQL directly. マネージド Mutex クラスはこれらのスレッドのアフィニティに関する注意事項を処理しないことに注意してください。Note that the managed Mutex class does not handle these thread affinity concerns.

マネージド スレッド ローカル記憶域やスレッドの現在の UI カルチャなど、マネージド Thread オブジェクトのほとんどの状態は安全に使うことができます。You can safely use most of the state on a managed Thread object, including managed thread local storage and the thread’s current UI culture. また、ThreadStaticAttribute を使うこともできます。これは、既存の静的変数の値を、現在のマネージド スレッドによってのみアクセスできるようにします (これは、CLR でファイバー ローカル記憶域を行うもう 1 つの方法です)。You can also use the ThreadStaticAttribute, which makes the value of an existing static variable accessible only by the current managed thread (this is another way of doing fiber local storage in the CLR). プログラミング モデルの理由から、SQL で実行しているときは、スレッドの現在のカルチャを変更できません。For programming model reasons, you can not change the current culture of a thread when running in SQL.

コード分析ルールCode Analysis Rule

SQL Server はファイバー モードで実行します。スレッド ローカル記憶域は使わないでください。SQL Server runs in fiber mode; do not use thread local storage. TlsAllocTlsFreeTlsGetValue、および TlsSetValue. のプラットフォーム呼び出しを行わないでください。Avoid platform invoke calls to TlsAlloc, TlsFree, TlsGetValue, and TlsSetValue.

SQL Server に偽装を処理させるLet SQL Server Handle Impersonation

偽装はスレッド レベルで動作し、SQL が実行できるのはファイバー モードなので、マネージド コードはユーザーを偽装してはならず、RevertToSelf を呼び出してはなりません。Since impersonation operates on the thread level and SQL can run in fiber mode, managed code should not impersonate users, and should not call RevertToSelf.

コード分析ルールCode Analysis Rule

SQL Server に偽装を処理させるようにします。Let SQL Server handle impersonation. RevertToSelfImpersonateAnonymousTokenDdeImpersonateClientImpersonateDdeClientWindowImpersonateLoggedOnUserImpersonateNamedPipeClientImpersonateSelfRpcImpersonateClientRpcRevertToSelfRpcRevertToSelfExSetThreadToken は使わないでください。Do not use RevertToSelf, ImpersonateAnonymousToken, DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, RpcImpersonateClient, RpcRevertToSelf, RpcRevertToSelfEx, or SetThreadToken.

Thread::Suspend を呼び出さないDo Not Call Thread::Suspend

スレッドを一時停止させる機能は単純な操作のように見えますが、デッドロックが発生する可能性があります。The ability to suspend a thread may appear a simple operation, but it can cause deadlocks. ロックを保持しているスレッドが第 2 のスレッドによって一時停止された後、第 2 のスレッドが同じロックを取得しようとすると、デッドロックが発生します。If a thread holding a lock gets suspended by a second thread and then the second thread tries taking the same lock, a deadlock occurs. 現在、Suspend はセキュリティ、クラスの読み込み、リモート処理、およびリフレクションを妨げる可能性があります。Suspend can interfere with security, class loading, remoting, and reflection currently.

コード分析ルールCode Analysis Rule

Suspend を呼び出さないでください。Do not call Suspend. 代わりに SemaphoreManualResetEvent などの実際の同期プリミティブの使用を検討してください。Consider using a real synchronization primitive instead, such as a Semaphore or ManualResetEvent .

制約された実行領域と信頼性のコントラクトを使って重大な操作を保護するProtect Critical Operations with Constrained Execution Regions and Reliability Contracts

共有状態を更新する複雑な操作、または完全に成功するか完全に失敗することが確定的に必要な複雑な操作を実行するときは、制約された実行領域 (CER) によって保護されるようにします。When performing a complex operation that updates a shared status or that needs to deterministically either fully succeed or fully fail, be sure that it is protected by a constrained execution region (CER). これにより、スレッドの突然の中止や突然の AppDomain のアンロードなど、すべてのケースでコードが実行されることが保証されます。This guarantees that the code runs in every case, even an abrupt thread abort or an abrupt AppDomain unload.

CER は、PrepareConstrainedRegions の呼び出しが直前にある特定の try/finally ブロックです。A CER is a particular try/finally block immediately preceded by a call to PrepareConstrainedRegions.

このようにすると、try ブロックを実行する前に finally ブロック内のすべてのコードを準備するよう、Just-In-Time コンパイラに指示されます。Doing so instructs the just-in-time compiler to prepare all the code in the finally block before running the try block. これにより、finally ブロック内のコードがすべてのケースでビルドされて実行されることが保証されます。This guarantees that the code in the finally block is built and will run in all cases. CER では空の try ブロックを使うことが珍しくありません。It is not uncommon in a CER to have an empty try block. CER を使うと、非同期スレッドの中止およびメモリ不足例外に対して保護されます。Using a CER protects against asynchronous thread aborts and out-of-memory exceptions. 非常に深いコードに対するスタック オーバーフローを追加で処理する CER の形式については、「ExecuteCodeWithGuaranteedCleanup」をご覧ください。See ExecuteCodeWithGuaranteedCleanup for a form of a CER that additionally handles stack overflows for exceedingly deep code.

関連項目See also