ロック階層違反

2 つのタスク実行で 2 つ以上のロックが異なる順番で取得されると、プログラムの並列実行時にデッドロックに繋がる可能性があります。

ロック階層違反の問題は次のような時系列で発生します。

タスク 1

  1. ロック A を取得します。

  2. ロック B を取得します。

  3. ロック B を解放します。

  4. ロック A を解放します。

タスク 2

  1. ロック B を取得します。

  2. ロック A を取得します。

  3. ロック A を解放します。

  4. ロック B を解放します。

2 つのタスクが並列に実行されるとき、これらのタイムラインが交互に実行されると、デッドロックが発生します。

  1. タスク 1: ロック A を取得します。

  2. タスク 2: ロック B を取得します。

  3. タスク 1: ロック B を取得しようとします; タスク 2 が解放するまで待機します。

  4. タスク 2: ロック A を取得しようとします; タスク 1 が解放するまで待機します。

依存関係ツールは、問題セットに複数の問題があるためロック階層違反を報告します。それぞれの問題は、単一スレッドの観点からロック階層違反を示します。

ロック階層違反の問題は、デッドロックの最も一般的な原因であり、ロック階層違反が報告されるとターゲットが並列実行された場合にデッドロックが生じる可能性があることを示しています。

構文

問題のタイプ: ロック階層違反

ID

コードの場所

説明

1

割り当てサイト

存在する場合、スレッドにより取得された同期オブジェクト (通常、最初に取得されたオブジェクト) が生成された位置と関連するコールスタックを示します。

2

並列サイト

存在する場合、ロック階層違反の問題を含む並列サイトの位置と、関連するコールスタックを示します。

3

ロック所有

タスクがロックを取得した場所と関連するコールスタックを示します。

4

ロック所有

タスクが最初のロックを保持している間に 2 番目のロックを取得した場所と関連するコールスタックを示します。

// タスク 1

ANNOTATE_LOCK_ACQUIRE(&lahv_lock1); 
ANNOTATE_LOCK_ACQUIRE(&lahv_lock2); /* ロック階層違反 */ 
ANNOTATE_LOCK_RELEASE(&lahv_lock2); 
ANNOTATE_LOCK_RELEASE(&lahv_lock1);

// タスク 2

ANNOTATE_LOCK_ACQUIRE(&lahv_lock2); 
ANNOTATE_LOCK_ACQUIRE(&lahv_lock1); /* ロック階層違反 */ 
ANNOTATE_LOCK_RELEASE(&lahv_lock1); 
ANNOTATE_LOCK_RELEASE(&lahv_lock2);

修正方法

インターリーブが可能であるか、またはインターリーブを妨げるほかの同期が存在するかどうかを調査します。インターリーブ可能である場合、次のオプションを検討します。

複数のロックではなく単一のロックを使用します.。

// タスク 1

ANNOTATE_LOCK_ACQUIRE(&lahv_lock1); 
a++; b += a; 
ANNOTATE_LOCK_RELEASE(&lahv_lock1);

// タスク 2

ANNOTATE_LOCK_ACQUIRE(&lahv_lock2); 
b += x[i]; a -= b; 
ANNOTATE_LOCK_RELEASE(&lahv_lock2);

すべてのタスクが同じロックのセットを同じ順番で取得するように、一貫性のある順序を定義します。

// タスク 1

ANNOTATE_LOCK_ACQUIRE(&lahv_lock1); 
a++; b += a; 
ANNOTATE_LOCK_RELEASE(&lahv_lock1);

// タスク 2

ANNOTATE_LOCK_ACQUIRE(&lahv_lock2); 
b += x[i]; a -= b; 
ANNOTATE_LOCK_RELEASE(&lahv_lock2);

タスクが複数のロックを要求する場合、取得した順番と逆の順番でロックを解放してください。