Skip to main content

ロック要求とデッドロックの詳細

ここでは、InterSystems IRIS® データ・プラットフォームにおけるロック要求の処理方法と、デッドロックのシナリオに関する詳細情報を提供します。

待機ロック要求

あるプロセスが排他ロックを保持する場合、別のプロセスが同じロック、または保持されたロックの上層や下層レベルのノード上のロックを取得しようとすると、待機状態が発生します。添え字付きグローバル (配列ノード) をロックする場合、以下のように、ユーザがロックするものと他のプロセスでロック可能なものとの区別が重要になります。

  • ユーザがロックするもの:ユーザは指定したノードに対してのみ明示的なロックを有します。その上層や下層のレベルのノードに対してはロックを有しません。例えば、^student(1,2) をロックする場合、ユーザは ^student(1,2) に対してのみ明示的なロックを有します。上層レベルのノード (^student(1) など) の解放によってこのノードを解放することはできません。なぜなら、上層レベルのノードに対して明示的なロックを有していないためです。もちろん、ユーザは任意の順序で上層または下層のノードを明示的にロックすることができます。

  • 他プロセスが何をロックできるか:ユーザがノードをロックすることにより、他のプロセスがその同一ノード、または上層や下層レベルのノード (該当ノードの親や子) をロックできません。親の ^student(1) をロックすることはできません。なぜなら、これをロックすると、子の ^student(1,2) (プロセスによって既に明示的にロックされている) も暗示的にロックされるためです。子の ^student(1,2,3) をロックすることはできません。なぜなら、プロセスが既に親の ^student(1,2) をロックしているためです。それらの他のプロセスは、指定の順序によりロック・キューにおいて待機となります。これらはロック・テーブルにリストされ、キュー内において他に優先することを指定された最上層レベルのノードで待機となります。これはロックされたノード、またはロックを待つノードとなる場合があります。

以下に例を示します。

  1. プロセス A は ^student(1,2) をロックします。

  2. プロセス B は ^student(1) のロックを試行しますが、禁じられます。これは、プロセス B が ^student(1) をロックすると、^student(1,2) も (暗示的に) ロックされるためです。ただし、プロセス A は ^student(1,2) に対するロックを保持しています。ロック・テーブルには、これが WaitExclusiveParent ^student(1,2) としてリストされます。

  3. プロセス C は ^student(1,2,3) のロックを試行しますが、禁じられます。ロック・テーブルには、これが WaitExclusiveParent ^student(1,2) としてリストされます。プロセス A は ^student(1,2) に対するロックを保持しており、そのため ^student(1,2,3) に対する暗示的なロックを保持しています。ただし、プロセス C はキュー内でプロセス B よりも下層となるため、プロセス B が ^student(1) をロックして解放するのをプロセス C は待つ必要があります。

  4. プロセス A は ^student(1,2,3) をロックします。待機ロックはそのままで変更ありません。

  5. プロセス A は ^student(1) をロックします。待機ロックは以下のように変化します。

    • プロセス B は WaitExclusiveExact ^student(1) としてリストされます。プロセス B は、プロセス A が保持するものと同一のロック (^student(1)) をロックすることを待ちます。

    • プロセス C は WaitExclusiveChild ^student(1) としてリストされます。プロセス C はプロセス B よりもキュー内で下層となるため、要求されたロックをプロセス B がロックして解放するのを待ちます。そのときには、プロセス C がプロセス B ロックの子をロックできるようになります。同様に、プロセス A が ^student(1) を解放するのをプロセス B は待ちます。

  6. プロセス A は ^student(1) をアンロックします。待機ロックは WaitExclusiveParent ^student(1,2) に戻ります。(手順 2 および 3 と同一。)

  7. プロセス A は ^student(1.2) をアンロックします。待機ロックは WaitExclusiveParent ^student(1,2,3) に変化します。プロセス B は ^student(1) (現在のプロセス A ロック ^student(1,2,3) の親) のロックを待ちます。プロセス C はプロセス B が ^student(1) (プロセス C により要求された ^student(1,2,3) ロックの親) をロックしてからアンロックするのを待ちます。

  8. プロセス A は ^student(1,2,3) をアンロックします。プロセス B は ^student(1) をロックします。プロセス C は現在、プロセス B によって禁じられています。プロセス C は WaitExclusiveChild ^student(1) としてリストされます。プロセス C は ^student(1,2,3) (現在のプロセス B ロックの子) のロックを待ちます。

配列ノードに対するロック要求のキュー

配列ロックに対する基本的なキュー・アルゴリズムでは、リソースが直接競合していない場合でも、同一リソースに対するロック要求は受信した順で厳密にキューに置かれます。この様子を以下の例に示します。ここでは、同じグローバル配列上の 3 つのロックが、以下に示す順序で別々のプロセスによって要求されます。

Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)

これらの要求のステータスは以下のとおりです。

  • プロセス A は ^x(1,1) に対するロックを保持しています。

  • プロセス B は、プロセス A が ^x(1,1) に対するロックを解除するまで ^x(1) をロックできません。

  • プロセス C もブロックされていますが、プロセス A のロックに伴うブロックではありません。プロセス B が ^x(1) の明示的なロックと、^x(1,2) の暗示的なロックを待機しており、これによりプロセス C がブロックされます。

シーケンスでロックを保持しているプロセスの後にある次のジョブを高速化するために、このような手法が採用されています。キューの中でプロセス C がプロセス B を飛び越えることができるようにすると、プロセス C は速く実行できますが、プロセス B に重大な遅延が発生する可能性があります。プロセス C のようなジョブが多数存在する場合は、特に顕著になります。

親ノードに対するロックを保持しているプロセスには、そのノードの子に対して要求されたロックが直ちに付与されます。これは、要求は受信した順で処理されるという一般的なルールの例外です。例えば、前の例の拡張を以下で考えます。

Process A: LOCK ^x(1,1)
Process B: LOCK ^x(1)
Process C: LOCK ^x(1,2)
Process A: LOCK ^x(1,2)

この例では、プロセス A には、プロセス B とプロセス C よりも前に、^x(1,2) に対して要求されたロックが直ちに付与されています。プロセス A が既に ^x(1,1) に対するロックを保持しているからです。

Note:

このプロセスのキューイング・アルゴリズムは、添え字を持つすべてのロック要求に適用されます。ただし、添え字のないロック要求 (LOCK +^x) と添え字のあるロック要求 (LOCK +^x(1,1)) の両方が待機中である場合、添え字のないロック (LOCK ^x など) の解除は特殊なケースです。この場合、どのロック要求が付与されるかは予測できず、プロセスのキューイングに従わない場合があります。

ECP ローカルおよびリモート・ロック要求

ロックを解除する際、ECP クライアントは、パフォーマンスを向上させるためにその他のシステム上の待機に優先してローカルの待機にロックを付与できます。リモート・ロック待機で許容できないほどの遅延が発生しないように、これが発生できる回数は制限されています。

デッドロックの回避

既存の共有ロックを保持している際の (+) 排他ロックの要求は、潜在的な危険を伴います。これは、"デッドロック"として知られる状況を引き起こす可能性があるからです。この状況は、既に他のプロセスによって共有ロックとしてロックされているロック名に対して、2 つのプロセスがそれぞれ排他ロックを要求するときに発生します。その結果、各プロセスは、他のプロセスが既存の共有ロックを解除するまで待機する間、停止します。

次の例では、これがどのように行われるかについて説明します (数字は処理の順番を示します)。

プロセス A プロセス B

1.LOCK ^a(1)#"S"

プロセス A は共有ロックを取得します。

 
 

2.LOCK ^a(1)#"S"

プロセス B は共有ロックを取得します。

3.LOCK +^a(1)

プロセス A は排他ロックを要求し、プロセス B がその共有ロックを解除するまで待機します。

 
 

4.LOCK +^a(1)

プロセス B は排他ロックを要求し、プロセス A がその共有ロックを解除するまで待機します。これによってデッドロックが発生します。

これは最も単純な形式のデッドロックです。デッドロックは、保持されているロックの親ノードまたは子ノード上のロックをプロセスが要求する際にも発生する可能性があります。

デッドロックを防止するには、プラス記号なしで排他ロックを要求する (そうすることで共有ロックをロック解除する) 必要があります。以下の例では、両方のプロセスが排他ロックを要求する際に、それぞれが有している以前のロックを解除することでデッドロックを防止しています (数字は操作の順序を示しています)。どのプロセスが排他ロックを取得するかに注意してください。

プロセス A プロセス B

1.LOCK ^a(1)#"S"

プロセス A は共有ロックを取得します。

 
 

2.LOCK ^a(1)#"S"

プロセス B は共有ロックを取得します。

3.LOCK ^a(1)

プロセス A は共有ロックを解除してから排他ロックを要求し、プロセス B がその共有ロックを解除するまで待機します。

 
 

4.LOCK ^a(1)

プロセス B は共有ロックを解除してから排他ロックを要求します。プロセス A は直ちに、要求した共有ロックを取得します。プロセス B は、プロセス A がその共有ロックを解除するまで待機します。

他のデッドロック回避方法には、LOCK + および LOCK - コマンドを実行する順序に関する、厳密なプロトコルに従う方法もあります。すべてのプロセスが、この同じ順序に従っている限り、デッドロックが発生することはありません。単純なプロトコルは、すべてのプロセスにおいて照合順序でロックを適用および解除するものです。

デッドロック状況の影響を最小限に抑えるために、プラス記号のロックを使用する際に timeout 引数を指定する必要があります。例えば、LOCK +^a(1):10 オペレーションは 10 秒後にタイムアウトします。

デッドロックが発生した場合は、管理ポータルまたは ^LOCKTAB ユーティリティを使用して、問題になっているロックのいずれかを削除できます。管理ポータルから、[ロックを管理] ウィンドウを開き、デッドロック・プロセスに対して [削除] オプションを選択します。

関連項目

FeedbackOpens in a new tab