デッドロック(デッドロック)とは | 意味や読み方など丁寧でわかりやすい用語解説
デッドロック(デッドロック)の意味や読み方など、初心者にもわかりやすいように丁寧に解説しています。
読み方
日本語表記
デッドロック (デッドロック)
英語表記
deadlock (デッドロック)
用語解説
デッドロックは、複数のプロセスやスレッドが互いにリソースの解放を待ち合わせ、結果としてどの処理も先に進めず、システム全体が停止したかのような状態に陥る現象である。これは、特に複数の処理が同時に動作する並行処理環境やデータベースシステムで発生しやすく、システムの可用性や安定性に深刻な影響を与える可能性がある。
デッドロックが発生する具体的な状況を理解するためには、まず「リソース」と「ロック(排他制御)」の概念を把握する必要がある。リソースとは、メモリ領域、ファイル、データベースの特定のレコード、入出力デバイスなど、プロセスやスレッドが利用するあらゆる対象を指す。これらのリソースは、整合性を保つため、同時に複数の処理から変更されることが許されない場合がある。このような状況で、一つの処理がリソースを使用している間、他の処理がそのリソースにアクセスできないようにする仕組みがロックである。ロックは排他制御を実現するための基本的な手段であり、処理がリソースを独占的に使用している間、他の処理からのアクセスをブロックする。
デッドロックは、主に二つ以上のプロセス(またはスレッド)が、二つ以上のリソースに対してロックを要求し、それぞれが相手が保持しているリソースを待つ「膠着状態」に陥ることで発生する。例えば、プロセスAがリソースXをロックしている状態でリソースYの解放を待つ一方、プロセスBがリソースYをロックしている状態でリソースXの解放を待つといった状況がそれに該当する。この状態では、プロセスAもプロセスBも、相手が保持するリソースが解放されるのを永遠に待ち続けることになり、どちらの処理も完了しない。
デッドロックが発生するには、以下の四つの条件が同時に成立する必要があると言われている。これらはコフマンの四つの条件として知られる。 一つ目は「相互排他」である。これは、少なくとも一つのリソースが共有不可能であり、一度に一つのプロセスしかそのリソースを使用できないことを意味する。もしリソースが完全に共有可能であれば、デッドロックは発生しない。 二つ目は「保持と待機」である。これは、あるプロセスが既に何らかのリソースを保持している状態で、さらに別のリソースの解放を待っていることを指す。リソースを保持したまま待機することが、デッドロックの起点となる。 三つ目は「非割込み」である。これは、プロセスが保持しているリソースが、そのプロセスによって明示的に解放されるまで、他のプロセスによって強制的に解放されることができない状態を指す。もしリソースを強制的に奪い取ることができれば、デッドロックは解消できる可能性がある。 四つ目は「循環待機」である。これは、複数のプロセスが環状にリソースを待ち合っている状態である。例えば、プロセスP1がP2が持つリソースを待ち、P2がP3が持つリソースを待ち、…、PnがP1が持つリソースを待つといった関係である。この循環がデッドロックの直接的な原因となる。
これらの条件のうち一つでも満たされないようにシステムを設計することで、デッドロックの発生を防ぐことができる。このアプローチを「デッドロック防止」と呼ぶ。デッドロック防止の具体例としては、まず「保持と待機」の条件を破る方法がある。これは、プロセスが実行を開始する前に必要な全てのリソースを一度に要求し、全てのリソースが取得できるまで一切のリソースを保持しないようにする方法である。しかし、この方法はリソースの利用効率を低下させる可能性がある。次に「非割込み」の条件を破る方法として、プロセスが必要なリソースを取得できない場合、現在保持している全てのリソースを自発的に解放させ、後で再度要求させるという戦略がある。最も実用的なのは「循環待機」の条件を破る方法である。これは、システム内の全てのリソースに一貫した順序を割り当て、プロセスが常に昇順にリソースを要求するようにルールを設けることで実現できる。例えば、リソースA、B、Cがある場合、必ずA→B→Cの順でロックを取得するように徹底すれば、循環待機は発生しない。
デッドロックへの対処法には、デッドロック防止の他に、「デッドロック回避」と「デッドロック検出と回復」がある。デッドロック回避は、システムがリソース割り当て要求を受けるたびに、将来デッドロックが発生しないかを事前に判断し、安全な状態を維持できる場合にのみリソースを割り当てる手法である。銀行家のアルゴリズムなどが知られているが、実行時にリソースの最大要求量を把握しておく必要があるなど、実現が難しい場合も多い。デッドロック検出と回復は、デッドロックの発生を許容し、定期的にシステムがデッドロック状態にあるかを検出する。デッドロックが検出された場合、デッドロックを解消するための回復措置を講じる。一般的な回復策としては、デッドロックに関与しているいずれかのプロセスを強制的に終了させる(ロールバックさせる)ことや、プロセスが保持しているリソースを強制的に解放させる(プリエンプション)ことなどが挙げられる。データベースシステムでは、デッドロックを検出すると、通常、デッドロックに関与するトランザクションのうちの一つを「犠牲者」として選び、そのトランザクションをロールバックさせてリソースを解放し、他のトランザクションが続行できるようにする。
システムエンジニアがデッドロックを考慮する際には、特にデータベーストランザクションの設計が重要になる。複数のトランザクションが同時に動作し、異なるテーブルやレコードに対してロックを取得する可能性がある場合、デッドロックが発生しやすい。例えば、トランザクションAがテーブルAのレコードXをロックし、次にテーブルBのレコードYを更新しようと待機する。同時にトランザクションBがテーブルBのレコードYをロックし、次にテーブルAのレコードXを更新しようと待機する。この状態は典型的なデッドロックである。これを避けるためには、トランザクションがリソースをロックする順序を統一する、ロックの粒度(ロックする範囲)を適切に設定する、あるいはトランザクションの実行時間を短縮するなどの工夫が必要となる。
デッドロックはシステムの停止やパフォーマンス低下に直結し、ユーザーエクスペリエンスを著しく損なう可能性がある。そのため、並行処理を伴うシステム設計やアプリケーション開発においては、デッドロックの発生条件を理解し、適切な防止、回避、または検出と回復の戦略を事前に計画することが不可欠である。特に、開発初期段階からリソースロックの取得順序やトランザクションの設計に注意を払い、デッドロックが発生しにくい堅牢なシステムを構築するよう努めるべきである。