私は多くの言語でプログラミングを行ってきましたが、自分のコードにデッドロックがあることを認識していません。
私はそれが起こらないことを意味するためにこれを取りました.
これは (データベースではなくプログラミングで) 頻繁に発生するので、心配する必要がありますか?
私は多くの言語でプログラミングを行ってきましたが、自分のコードにデッドロックがあることを認識していません。
私はそれが起こらないことを意味するためにこれを取りました.
これは (データベースではなくプログラミングで) 頻繁に発生するので、心配する必要がありますか?
デッドロックが発生する可能性があるのは、次の 2 つの条件が当てはまる場合です。つまり、複数のスレッドがあり、それらが複数のリソースに対して競合している場合です。
マルチスレッド コードを記述しますか? これは、独自のスレッドを開始することによって明示的に行うことも、スレッドが目に見えないところで作成されるフレームワークで作業することもあり、そのため、コードでそれを確認することなく複数のスレッドで実行しています。
例: Java サーブレット API。サーブレットまたは JSP を作成します。アプリ サーバーにデプロイします。何人かのユーザーがあなたの Web サイト、つまりサーブレットにアクセスしました。サーバーには、ユーザーごとにスレッドがある可能性があります。
リクエストを処理する際に、いくつかのリソースを取得したい場合に何が起こるかを考えてみましょう:
if ( user Is Important ){
getResourceA();
}
getResourceB();
if (today is Thursday ) {
getResourceA();
}
// some more code
releaseResourceA();
releaseResoruceB();
上記の不自然な例で、木曜日に重要なユーザーのリクエストが到着し、重要でないユーザーのリクエストが多かれ少なかれ同時に到着したときに何が起こるかを考えてみてください。
重要なユーザーのスレッドはリソース A を取得し、B を要求します。重要度の低いユーザーはリソース B を取得し、A を要求します。どちらも、すでに所有しているリソースを手放しません ... デッドロック。
これは、同期を明示的に使用するコードを記述している場合、実際には非常に簡単に発生する可能性があります。ほとんどの場合、データベースを使用しているときに発生しますが、幸いなことに、データベースには通常デッドロック検出機能があり、どのようなエラーが発生したかを見つけることができます。
デッドロックに対する防御:
それが実際にどのくらいの頻度で発生するか (製品コードで? 開発で?) を推測するのは非常に困難です。(非常に多くの場合、デッドロックは非常に特定の状況でのみ発生します。)
いくつかの発生を見てきましたが、最近見たのは、接続を取得しようとする別のスレッドと同時にファイナライザーが実行されたため、(データベースではなく) Oracle ドライバーで発生しました。幸いなことに、そもそもファイナライザーの実行を回避できる別のバグを見つけました...
基本的にデッドロックは、ほとんどの場合、別のスレッド (A) を保持している間に 1 つのロック (B) を取得しようとする一方で、別のスレッドがまったく同じことを逆に実行することが原因です。1 つのスレッドが B が解放されるのを待っていて、B を保持しているスレッドが A が解放されるのを待っている場合、どちらももう一方を続行させません。
常に同じ順序でロックを取得する (そして逆の順序で解放する) ことを確認してください。ほとんどの場合、デッドロックを回避できるはずです。
2 つのロックを直接持たない奇妙なケースもありますが、基本的な原則は同じです。たとえば、.NET ではControl.Invoke
、UI スレッドで UI を更新するために、ワーカー スレッドから を使用できます。Invoke
更新が処理されるまで待ってから続行するようになりました。バックグラウンド スレッドが更新が必要なロックを保持しているとします... 繰り返しますが、ワーカー スレッドは UI スレッドを待機していますが、ワーカー スレッドがロックを保持しているため、UI スレッドは続行できません。再びデッドロック。
これは要注意パターンです。必要な場所だけをロックし、できるだけ短い期間だけロックし、すべてのコードのスレッド セーフとロック ポリシーを文書化するようにすれば、デッドロックを回避できるはずです。ただし、すべてのスレッド トピックと同様に、言うは易く行うは難しです。
機会があれば、Java Concurrency in Practiceの最初の数章を見てください。
デッドロックは、並列プログラミングのどの状況でも発生する可能性があるため、処理する同時実行数によって異なります。並行プログラミングの例としては、マルチプロセス、マルチスレッド、マルチスレッドを導入するライブラリなどがあります。UI フレームワーク、イベント処理 (タイマー イベントなど) はスレッドとして実装できます。Web フレームワークは、複数の Web 要求を同時に処理するスレッドを生成できます。マルチコア CPU を使用すると、以前よりも多くの同時状況を視覚的に確認できる場合があります。
A が B を待機しており、B が A を待機している場合、循環待機によりデッドロックが発生します。したがって、作成するコードの種類にも依存します。分散トランザクションを使用すると、そのようなシナリオを簡単に引き起こすことができます。分散トランザクションがなければ、銀行口座がお金を盗むリスクがあります。
デッドロックの一般的な原因は、さまざまなスレッド (またはプロセス) が一連のリソースを異なる順序で取得した場合です。
たとえば、リソース A と B がある場合、スレッド 1 が A を取得してから B を取得し、スレッド 2 が B を取得してから A を取得すると、デッドロックが発生するのを待っています。
この問題には簡単な解決策があります。すべてのスレッドが常に同じ順序でリソースを取得するようにします。たとえば、すべてのスレッドが A と B をこの順序で取得すると、デッドロックを回避できます。
すべては、コーディングする内容によって異なります。ロックを使用しない従来のシングル スレッド アプリケーション。あまり。
複数のロックを伴うマルチスレッド コードは、デッドロックの原因となります。
適切な例外処理なしで 7 つの異なるロックを使用するコードのリファクタリングを終了しました。これには多くのデッドロックの問題がありました。
デッドロックとは、2 つのプロセスが相互に依存している状況です。一方が他方より先に終了することはありません。したがって、一度に複数のコード フローを実行している場合にのみ、コードでデッドロックが発生する可能性があります。
マルチスレッド アプリケーションを開発するということは、デッドロックを考慮する必要があることを意味します。シングル スレッド アプリケーションでデッドロックが発生する可能性はほとんどありませんが、不可能ではありません。