DA0039: 非常に高率のロック競合

Visual Studio 2017 RC の最新のドキュメントの詳細については、Visual Studio 2017 RC ドキュメントをご参照ください。

規則 ID DA0039
分類 .NET Framework の使用
プロファイル方法 サンプリング

インストルメンテーション

.NET メモリ
メッセージ 非常に高率の .NET ロック競合が発生しています。 同時実行プロファイルを実行し、このロック競合の原因を調査してください。
規則の種類 警告

サンプリング、.NET メモリ、またはリソース競合メソッドを使用してプロファイリングを行うときは、この規則を呼び出すためのサンプルを少なくとも 25 個収集する必要があります。

原因

プロファイル データを使用して収集したシステム パフォーマンス データは、アプリケーションの実行中に極端に高率のロック競合が発生したことを示しています。 競合の原因を見つけるために、同時実行プロファイル方法を使用して、プロファイリングを再度実行することを検討してください。

規則の説明

ロックは、マルチスレッド アプリケーション内で、一度に 1 つのスレッドで連続的に実行する必要があるコードのクリティカル セクションを保護するために使用されます。 Microsoft .NET 共通言語ランタイム (CLR: Common Language Run-time) には、同期とロックのプリミティブの完全なセットが用意されています。 たとえば、C# 言語ではロック ステートメントがサポートされています (Visual Basic では SyncLock)。 マネージ アプリケーションは、System.Threading 名前空間内で Monitor.Enter メソッドと Monitor.Exit メソッドを呼び出すことで、ロックを直接取得および解放できます。 .NET Framework は、ミューテックス、ReaderWriter ロック、およびセマフォをサポートするクラスをはじめとする、追加の同期と競合のプリミティブをサポートします。 詳細については、MSDN Web サイトの Overview of Synchronization Primitives .NET Framework 開発者ガイド"で、参照します。 .NET Framework のクラスは、それ自体が、Windows オペレーティング システムに組み込まれている下位のレベルの同期サービスの上層に配置されています。 下位レベルのサービスには、クリティカル セクション オブジェクト、および多数のさまざまな待機機能やイベント通知機能が含まれます。 詳細については、MSDN ライブラリ 同期 の Win32 および COM 開発のセクションを参照します

同期と競合に使用される .NET Framework クラスとネイティブの Windows オブジェクトは両方とも、共有メモリの位置を基にしています。これは、インタロックされた操作を使用して変更する必要があります。 インタロックされた操作では、共有メモリの位置を操作するハードウェア固有の命令を使用して、分割不可能な操作によってその状態を変更します。 分割不可能な操作は、コンピューター内のすべてのプロセッサにわたって一貫していることが保証されています。 Locks と WaitHandles は、設定およびリセットされるときに自動的にインタロックされた操作を使用する .NET オブジェクトです。 アプリケーション内には、スレッド セーフな方法で更新するためにはインタロックされた操作も使用する必要がある、その他の共有メモリ データ構造体が存在する場合があります。 詳細については MSDN ライブラリ インタロックされた操作 の .NET Framework セクションで、参照します

同期とロックは、マルチスレッド アプリケーションが正しく実行されるようにするために使用される機構です。 マルチスレッド アプリケーションの各スレッドは、独立した実行単位であり、オペレーティング システムによって個別にスケジュールされます。 ロックの競合は、あるスレッドがロックを保持しているために、ロックを取得しようとしている別のスレッドが遅延されると発生します。

ロックはしばしば入れ子になります。 入れ子は、クリティカル セクションを実行中のスレッドがある関数を実行し、その関数が別のロックを要求すると発生します。 ある程度のロックの入れ子は回避できません。 クリティカル セクションでは、スレッド セーフで実行されるように、ロックに依存する .NET Framework メソッドを呼び出すことがあります。 アプリケーション内のあるクリティカル セクションから Framework メソッドが呼び出され、このメソッドも異なるロック ハンドルを使用してロックを要求する場合、ロックが入れ子になります。 入れ子になったロック状態は、解消および修復が困難とされているパフォーマンス上の問題につながる可能性があります。

この規則は、プロファイリング実行中に取得された測定値により、ロック競合量が過度に多いことが示された場合に適用されます。 ロックの競合により、ロックを待機しているスレッドの実行が遅延します。 最低限のハードウェアで実行される単体テストまたはロード テストでの少量のロックの競合であっても、調査する必要があります。

注意

プロファイル データ中の、報告されたロックの競合の比率が高いが過度ではない場合、この警告メッセージではなく "DA0038: 高率のロック競合" の情報メッセージが適用されます。

警告の調査方法

メッセージをダブルクリックして、プロファイル データの [マーク] ビューに移動します。[.NET CLR LocksAndThreads\Contention Rate \/ sec] 列を探します。 ロックの競合が他のフェーズよりも多い特定のプログラム実行フェーズがあるかどうかを確認します。

この規則は、同時実行プロファイル方法を使用していない場合にのみ適用されます。 同時実行プロファイル方法は、アプリケーション内でのロックの競合に関連するパフォーマンス上の問題を診断するのに最適なツールです。 同時実行プロファイル データを収集して、アプリケーションのロック動作を確認してください。 これには、競合の多いロックはどれであるか、実行時間の長いスレッドは競合したロックを待機してどのように遅延するか、および示される特定のコードはどれであるかの確認が含まれます。 同時実行プロファイルは、すべてのロック競合についてデータを収集します。これには、ネイティブの Windows 機能、.NET Framework クラス、およびアプリケーションで参照するその他すべてのサードパーティ ライブラリが含まれます。 Visual Studio IDE からの同時実行プロファイル方法については、「スレッドおよびプロセスの同時実行データの収集」を参照してください。 コマンド ラインからの同時実行プロファイル方法に関する情報へのリンクについては、「コマンド ラインからのプロファイル方法の使用」の「Using the Concurrency Method to Collect Resource Contention and Thread Activity Data」セクションを参照してください。