web-dev-qa-db-ja.com

デッドロックの一般的な理由は何ですか?

デッドロックは見つけるのが難しく、取り除くのがとても不快です。

コードでデッドロックのエラーソースを見つけるにはどうすればよいですか? 「デッドロックパターン」はありますか?

私の特別なケースでは、データベースを扱いますが、この質問はすべてのデッドロックに対して開かれています。

39
guerda

更新:この最近のMSDNの記事 同時実行の問題を特定するためのツールとテクニック も興味深いかもしれません


MSDN記事のStephen Toub Deadlock monitor は、デッドロックが発生するために必要な次の4つの条件を述べています。

  • 特定のリソースの限られた数。 C#のモニター(lockキーワードを使用するときに使用するもの)の場合、モニターは相互排他ロック(一度に1つのスレッドのみがモニターを所有できることを意味する)であるため、この制限された数は1です。

  • 1つのリソースを保持し、別のリソースを要求する機能。 C#では、これはあるオブジェクトをロックしてから、最初のロックを解除する前に別のオブジェクトをロックするのと同じです。次に例を示します。


lock(a)
{
...
    lock(b)
    {
            ...
    }
}
  • プリエンプション機能はありません。 C#では、これは、あるスレッドが別のスレッドに強制的にロックを解放させることができないことを意味します。

  • 循環待ち状態。これは、スレッドのサイクルが存在することを意味します。各スレッドは、次のリソースが解放されるのを待ってから続行できます。

彼はさらに、デッドロックを回避する方法は条件4を回避する(または阻止する)ことであると説明しています。

Joe Duffyはいくつかの手法について説明しています デッドロックを回避および検出するためのもの(ロックの平準化として知られているものを含む)。ロックの平準化では、ロックには数値が割り当てられ、スレッドは、すでに取得しているロックよりも大きい番号のロックのみを取得する必要があります。これにより、サイクルの可能性を防ぎます。また、今日の典型的なソフトウェアアプリケーションでうまく機能することはしばしば困難であり、すべてのロック取得でロックの平準化に失敗すると、デッドロックが発生します。

29
Mitch Wheat

古典的なデッドロックシナリオは、AがロックXを保持していてロックYを取得したい一方で、BがロックYを保持していてロックXを取得したいというものです。中古)。

この場合、AとBが同じ順序でロックを取得すると、デッドロックを回避できます。

14
Brian Rasmussen

私の知る限りではデッドロックのパターンはありません(そして12年間に渡りマルチスレッドのトレーディングアプリケーションを作成していました)。

http://www.randomtree.org/eric/techblog/archives/2004/10/multithreading_is_hard.html

基本的に、(dotnet/c#で)すべての「lock(xxx)」ステートメントを「using TimedLock.Lock(xxx)」で検索/置換します

デッドロックが検出された場合(指定されたタイムアウト内にロックを取得できない場合、デフォルトでは10秒)、例外がスローされます。私のローカルバージョンもスタックトレースをすぐにログに記録します。スタックトレースをたどって(できればデバッグ番号と行番号を付けて)、障害発生時に保持されていたロックと、取得しようとしたロックをすぐに確認できます。

Dotnet 1.1では、前述のデッドロック状態では、運が良ければロックされたすべてのスレッドが同時に例外をスローします。したがって、2つ以上のスタックトレースと、問題を修正するために必要なすべての情報が得られます。 (2.0+は内部的にスレッドモデルを変更している可能性があるので、これは幸運ではありません。よくわかりません)

8
Peter Drier

すべてのトランザクションが同じ順序でテーブルに影響を与えることを確認することが、最も一般的なデッドロックを回避するための鍵です。

例えば:

トランザクションA

UPDATE Table A SET Foo = 'Bar'
UPDATE Table B SET Bar = 'Foo'

トランザクションB

UPDATE Table B SET Bar = 'Foo'
UPDATE Table A SET Foo = 'Bar'

トランザクションAがテーブルAのロックを取得し、トランザクションBがテーブルBのロックを取得するため、これによりデッドロックが発生する可能性が非常に高いため、どちらもロックを取得しません。もう一方が完了するまで、2番目のコマンド。

他のすべての形式のデッドロックは、リソースを割り当てている間の内部での集中的な使用とSQL Serverのデッドロックによって一般的に発生します。

8
Robin Day

はい-プロセスがランダムな順序でリソースを取得しようとすると、デッドロックが発生します。すべてのプロセスが同じリソースを同じ順序で取得しようとする場合、デッドロックの可能性は排除されないまでも大幅に削減されます。

もちろん、これは常に簡単にアレンジできるとは限りません...

4
anon

Herb Sutter でこの記事を読むことをお勧めします。デッドロックの問題の背後にある理由を説明し、この問題に取り組むためのフレームワークを この記事 に提示します。

2
Alan

最も一般的な(私の非科学的な観察によると)DBデッドロックのシナリオは非常に簡単です。

  • 2つのプロセスが何か(DBレコードなど)を読み取り、両方が関連リソース(通常はDBページ)の共有ロックを取得します。
  • どちらも更新を試み、ロックを排他的なロックにアップグレードしようとします-出来上がり、デッドロック。

これは、読み取りの後に更新が続く場合は、「FOR UPDATE」句(または特定のRDBMSに応じて同様)を指定することで回避できます。このようにして、プロセスは最初から排他ロックを取得し、上記のシナリオを不可能にします。

1
Rafał Dowgird

2つのプロセスがそれぞれ他のプロセスが先行する前に完了するのを待機しているときに発生する条件。その結果、両方のプロシージャがハングします。その最も一般的なマルチタスクとクリント/サーバー。

1
karan gujjar

典型的なシナリオは、不一致の更新計画です(テーブルが常に同じ順序で更新されるとは限りません)。ただし、処理量が多い場合にデッドロックが発生することは珍しくありません。

私はデッドロックを現実の事実として受け入れる傾向があります。それはいつか発生するため、DALでデッドロック処理を処理して再試行する準備をします。

1
Otávio Décio

デッドロックを回避するために、 Bankerのアルゴリズム と呼ばれるアルゴリズムがあります。

これは、デッドロックを回避するために役立つ情報 も提供します。

0
HuntM

デッドロックは主に、複数の依存ロックが存在する場合に発生します。スレッドで別のスレッドが逆の順序でミューテックスをロックしようとすると発生します。デッドロックを回避するためにミューテックスを使用することに注意を払う必要があります。

ロックを解除してから操作を完了してください。アクセス順序がABCであるなど、複数のロックがある場合、解放順序もABCである必要があります。

0
Marcus Thornton

前回のプロジェクトで、SQL Serverデータベースのデッドロックの問題に直面しました。理由を見つける際の問題は、私のソフトウェアとサードパーティのソフトウェアが同じデータベースを使用しており、同じテーブルで作業していることでした。デッドロックの原因を突き止めることは非常に困難でした。最終的には、sql-queryを作成して、どのプロセスがどのsql-Statementsがデッドロックを引き起こしているかを確認しました。そのステートメントはここにあります: SQL-Serverのデッドロック

0
Thomas Reimelt