FE EXAM

2相ロック(2フェーズロック)

ロックの獲得段階と解放段階を分けて直列化可能性を保証する制御方式。

INTERACTIVE VISUALIZATION
成長期
縮退期
フェーズ
idle
T1の保持ロック数
0
段階
シナリオ
ステップ1 / 7
STEP 1/7開始前 — 2つのデータA・Bを使う2相ロックは、ロックの「獲得だけする時期」と「解放だけする時期」をきっちり2つに分ける制御方式です。T1(=トランザクション1)がデータAとデータBの両方を使う処理を例に見ていきます。T2は同じデータを使いたくて待っています。
012保持ロック数時間 →成長期(獲得のみ)縮退期(解放のみ)頂点トランザクション(保持中のロック)T1待機中T2待機中
解説

📌
2相ロックとは

成長期(増える)縮退期(減る)頂点

2相ロック(2フェーズロック)とは、ロックの獲得段階(成長期)と解放段階(縮退期)をきっちり2つに分け、いったん解放を始めたら新しいロックは取らないという制御方式です。保持ロック数のグラフは必ず山型(増えてから減る)になります。

身近な例で考えると、料理で必要な道具を全部そろえてから調理を始め、終わったらまとめて片付けるのに似ています。途中で道具を返してはまた借りる、を繰り返すと混乱しますが、「先に全部そろえる→使う→まとめて返す」と分けると整理されます。

上のツールで▶ボタンを押すと、T1がデータA・Bのロックを次々に獲得(成長期)し、頂点を過ぎたら解放だけを行う(縮退期)様子と、保持ロック数が山型になる様子を確認できます。

📈
2フェーズの意味

① 成長期ロックを取るだけ② 縮退期ロックを返すだけ

「2相(2つの段階)」とは、次の2つの時期のことです。
成長期(lock phase):必要なロックを獲得していく時期。この間は解放してはいけない
縮退期(unlock phase):取ったロックを解放していく時期。この間は新たに獲得してはいけない

最大のルールは、一度でもロックを解放したら(縮退期に入ったら)、二度と新しいロックを取ってはいけないという点です。これを守ると保持ロック数のグラフが必ず山型になり、途中でギザギザ(増えたり減ったりの繰り返し)にはなりません。グラフの折り返し地点が「頂点」です。

直列化可能性

T1T2同じ結果1つずつ順番に実行

2相ロックを守ると、直列化可能性(serializability)が保証されます。直列化可能性とは、複数のトランザクションを並行で動かしても、結果が「1つずつ順番(直列)に実行したのと同じ正しさ」になる性質のことです。

なぜ保証できるのでしょうか。それは、「必要なロックを全部そろえてから(頂点)使い、まとめて手放す」ことで、あるトランザクションが使っている最中に別のトランザクションが割り込む隙がなくなるからです。割り込みがなければ、結果が入り乱れて矛盾することもありません。

ただし注意点もあります。2相ロックは正しさを保証しますが、デッドロック(互いに相手のロック解放を待ち続けて止まる状態)までは防げません。デッドロックは別の対策(検出・回避)が必要です。上のツールの最終ステップで、T1が完全に解放してからT2が動く流れを確認できます。

🔍
なぜ2相に分けると直列化できるのか

× 2相なし:T1が解放中にT2が割り込むT1: A取得T1: A解放T1: B取得T2: A取得・変更T1がAを手放した後にT2が書き換え → 結果が乱れる○ 2相あり:頂点まで全部確保してから作業成長期: A・B確保縮退期: まとめて解放

「なぜ2相に分けると直列化できるのか?」 — 結論から言うと、必要なロックを全部そろえてから(頂点)作業し、終わったらまとめて解放することで、他のトランザクションが割り込める隙を作らないからです。

2相をなしにすると次のような問題が起きます。
・T1がロックAを取得 → T1がAを解放 → T2がAを取得して値を書き換える → T1がBを取得
この場合、T1がAを使っている最中にT2が割り込んでAを書き換えてしまいます。T1は「書き換え前」の状態で話を進めているのに、実際のデータは変わっている — という矛盾が生まれます。

一方で2相ロックを守ると、T1が頂点(A・B両方確保)に達するまでAを手放しません。T2はAが欲しくても待つしかないため、割り込めません。割り込みがない = T1の処理が「1つずつ順番に実行」したのと同じ流れになるため、正しい結果が保証されます。

身近な例で考えると、試験の答案用紙を書き終わるまで手放さないのに似ています。採点者(他のトランザクション)が途中の答案をのぞいて採点し始めると、変更前・変更後のどちらの答えを採点したのか分からなくなります。提出(縮退期に入って全解放)してから採点させれば、途中介入はなくなります。

⚠️
2相ロックでもデッドロックは起きる

T1Aを保持・Bを要求T2Bを保持・Aを要求成長期中に互いを待つ → デッドロック

2相ロックが保証するのは「直列化可能性」だけです。デッドロックは防げません。

なぜデッドロックが起きるのかというと、2相ロックの「成長期」中はロックを追加取得し続けてよいルールになっているからです。T1がAを持ったままBを要求し、T2がBを持ったままAを要求すると、両者ともに成長期のまま互いの解放を待つ「循環待ち(=デッドロック)」が成立してしまいます。

2相ロックが守っているルールは「解放し始めたら新しいロックを取るな」です。でもこのルールは「取得の順番をどうするか」は何も決めていません。だから、複数のトランザクションが異なる順番でロックを取りに行くと、成長期の途中でぶつかってデッドロックになることがあります。

デッドロックへの対処は別に用意する必要があります。
検出してロールバック(=待ちグラフに循環が生じたら一方を強制中断)
ロック取得順序の統一(全員が「必ずA→Bの順」などと決めると循環ができない)
タイムアウト(一定時間取れなければあきらめて中断)

練習問題

🎯
基本情報技術者 練習問題

Q1.2相ロック方式の説明として最も適切なものはどれか。
A.ロックの獲得段階と解放段階を分け、いったん解放を始めたら新たなロックを取らない方式
B.ロックを2種類だけ用意する方式
C.すべてのロックを2回ずつ取得する方式
D.ロックをまったく使わずにデータを書き換える方式
Q2.2相ロックの「2相(2つの段階)」が指すものはどれか。
A.読み取り段階と書き込み段階
B.ロックを増やすだけの成長期と、減らすだけの縮退期
C.コミット段階とロールバック段階
D.通信段階と保存段階
Q3.2相ロックを守ることで保証されるものはどれか。
A.トランザクションが必ず高速に終わること
B.デッドロックが絶対に起きないこと
C.並行実行しても、1つずつ順番に実行したのと同じ正しい結果(直列化可能性)になること
D.データが暗号化されること

関連コンテンツ