Skip to main content

This is documentation for Caché & Ensemble. See the InterSystems IRIS version of this content.Opens in a new tab

For information on migrating to InterSystems IRISOpens in a new tab, see Why Migrate to InterSystems IRIS?

LOCK

データ・リソースへのアクセスを制御するために、プロセスがロックを適用および解除できるようにします。

Synopsis

LOCK:pc
L:pc

LOCK:pc +lockname#locktype:timeout,...
L:pc +lockname#locktype:timeout,...

LOCK:pc +(lockname#locktype,...):timeout,...
L:pc +(lockname#locktype,...):timeout,...

引数

pc オプション — 後置条件式。

+

オプション — ロックを適用または削除するロック・オペレーション・インジケータ (1 つの + 文字、– 文字、または文字なし) です。+ (プラス記号) は、既存のどのロックもアンロックせずに、指定されたロックを適用します。これは、増分ロックを適用するために使用できます。– (マイナス記号) は、ロックをアンロック (またはデクリメント) します。このロック・オペレーション・インジケータを省略すると (文字なし)、Caché では、既存のすべてのロックをアンロックし、指定されたロックを適用します。
lockname ロック、またはロック解除されるリソースと関連付けられているロック名。ローカル変数またはグローバル変数と同じ名前付け規約に従った正当な識別子でなければなりません。
#locktype オプション — ロックまたはアンロックするロックのタイプを指定する文字コードであり、引用符で囲んで指定します。使用可能な値は、“S” (共有ロック)、“E” (エスカレート・ロック)、“I” (即時アンロック)、および “D” (遅延アンロック) です。指定する場合、先頭の # 記号は必須です。例えば、#"S" となります。複数の文字コードを指定することができます。 例えば、#"SEI" と指定できます。“S” および “E” は、ロックとアンロックのどちらのオペレーションにも指定されます。“I” および “D” は、アンロック・オペレーションのみに指定されます。省略されると、ロックのタイプは既定の排他ロックになり (非 S)、エスカレートせず (非 E)、常に現在のトランザクションの最後まで、アンロックされたロックの解除を延期します (非 I / 非 D)。
:timeout オプション — 試行したロック・オペレーションがタイムアウトする前に待機する時間。オプションの #locktype の有無に関係なく指定できます。指定した場合、先頭の : 記号は必須です。例えば、LOCK ^a(1):10 または LOCK ^a(1)#"E":10 のようにします。timeout は、整数の秒単位で指定されます。値 0 を指定すると、1 回試行した後、タイムアウトします。秒の小数部は整数部分に切り捨てられます。省略した場合、Caché では無限に待機となります。

概要

LOCK コマンドには、以下の 2 つの基本的な形式があります。

引数なしの LOCK

引数なしの LOCK は、プロセスによって現在保持されているロックをすべて解除 (アンロック) します。これにはローカルとグローバルの両方の、排他ロックと共有ロックが含まれます。また、累積した増分ロックもすべて含まれます。例えば、任意のロック名に 3 つの増分ロックが設定されている場合、Caché は 3 つのロックすべてを解除し、ロック・テーブルからそのロック名のエントリを削除します。

トランザクション中に引数なし LOCK を発行すると、Caché は現在プロセスにより保持されているすべてのロックを、トランザクションの終わりまでロック解除状態にします。トランザクションが終了すると、Caché はロックを解除し、対応するロック名のエントリをロック・テーブルから削除します。

以下の例は、トランザクション中のさまざまなロックに適用され、それらすべてのロックを解除するために引数なし LOCK を発行します。ロックは、トランザクションの終了までロック解除状態になります。HANG コマンドを実行すると、ロック・テーブルにあるロックの ModeCount を確認する時間を取ることができます。

  TSTART
  LOCK +^a(1)      // ModeCount: Exclusive
  HANG 2
  LOCK +^a(1)#"E"  // ModeCount: Exclusive/1+1e
  HANG 2
  LOCK +^a(1)#"S"  // ModeCount: Exclusive/1+1e,Shared
  HANG 2
  LOCK             // ModeCount: Exclusive/1+1e->Delock,Shared->Delock
  HANG 10
  TCOMMIT          // ModeCount: locks removed from table

引数なし LOCK は、プロセスにより保持されているすべてのロックを、ロックを適用せずに解除します。プロセスを完了することでも、そのプロセスに保持されているすべてのロックを解除することができます。

引数付きの LOCK

引数付きの LOCK は、ロックとアンロックのオペレーションを行う、1 つまたは複数のロック名を指定します。Caché が行うロック・オペレーションは、使用するロック・オペレーション・インジケータ引数により異なります。

  • LOCK lockname は、プロセスにより事前に保持されていたすべてのロックをアンロックし、指定されたロック名にロックを適用します。

  • LOCK +lockname は、前のすべてのロックをアンロックすることなく、指定されたロック名にロックを適用します。これにより、さまざまなロックを累積させて、増分ロックを同じロックに適用できます。

  • LOCK -lockname は、アンロック・オペレーションを、指定されたロック名に対して実行します。アンロックは、指定されたロック名に対するロック・カウントをデクリメントします。このロック・カウントが 0 までデクリメントされると、ロックは解除されます。

ロック・オペレーションは、即時にロックを適用する場合もあれば、別のプロセスによる競合ロックが解除されるまでロック要求を待機キューで保留にする場合もあります。待機中のロック要求は (タイムアウトが指定されていれば) タイムアウトする場合もあり、無制限に (プロセスの終了まで) 待機する場合もあります。

複数のロック名が指定された LOCK

1 つの LOCK コマンドで複数のロックを指定する場合は、以下の 2 とおりの方法を使用できます。

  • 括弧なし :コンマ区切りリストとして複数の括弧なしのロック引数を指定すると、それぞれが独自のタイムアウトを持つ複数の非依存ロック・オペレーションを指定できます。(機能的には、この方法は、ロック引数ごとに個々の LOCK コマンドを指定する方法と同じです。)ロック・オペレーションは、厳密に左から右の順で実行されます。以下はその例です。

      LOCK var1(1):10,+var2(1):15

    括弧なしの複数のロック引数はそれぞれ、独自のロック・オペレーション・インジケータと、独自のタイムアウト引数を持つことができます。しかし、複数のロック引数を使用する場合、プラス記号ロック・オペレーション・インジケータなしのロック・オペレーションは、同じ LOCK コマンドの初期部分で適用されたロックを含む、既存のすべてのロックをアンロックします。例えば、コマンド LOCK ^b(1,1), ^c(1,2,3), ^d(1) は、次のような 3 つの独立したロック・コマンドとして解析されます。1 つ目は、プロセスが事前に保持していたロックがあればそれを解除して ^b(1,1) をロックし、2 つ目は即時に ^b(1,1) を解除して ^c(1,2,3) をロックし、3 つ目は即時に ^c(1,2,3) を解除して ^d(1) をロックします。結果として、^d(1) のみがロックされます。

  • 括弧付き : ロック名のコンマ区切りリストを括弧で囲むことで、複数のロックに対するロック・オペレーションを単独のアトミック処理として実行することができます。例えば、以下のようにすることができます。

      LOCK +(var1(1),var2(1)):10

    括弧内にリストされているすべてのロック・オペレーションは、単一のロック・オペレーション・インジケータと単一のタイムアウト引数によって管理されています。すべてのロックが適用されるか、またはいずれのロックも適用されないかのいずれかになります。プラス記号ロック・オペレーション・インジケータなしの、括弧で囲まれたリストは、既存のすべてのロックをアンロックし、リストされているすべてのロック名をロックします。

引数

pc

コマンドを条件付きにする、オプションの後置条件式です。Caché は、後置条件式が True (0 以外の数値) の場合に LOCK コマンドを実行します。Caché は、後置条件式が False (0 に評価される) の場合はコマンドを実行しません。引数なしの LOCK コマンドまたは引数付きの LOCK コマンドには、後置条件式を指定できます。詳細は、"Caché ObjectScript の使用法" の "コマンド後置条件式" を参照してください。

lock operation indicator

ロック・オペレーション・インジケータは、ロックの適用 (ロック) または削除 (アンロック) に使用されます。これは以下のいずれかの値を指定できます。

なし 現在のプロセスに属している既存のすべてのロックをアンロックし、指定されたロックの適用を試みます。例えば、LOCK ^a(1) は、プロセスにより事前に保持されていたすべてのロックを (ローカルまたはグローバル、排他または共有、エスカレートまたは非エスカレートのどちらであっても) 解除し、^a(1) のロックを試みるという、アトミック処理を実行します。これは次の 2 つの結果のいずれかになります。(1) 既存のすべてのロックはアンロックされ、^a(1) はロックされます。(2) 既存のすべてのロックはアンロックされ、^a(1) は別のプロセスによる競合ロックが解除されるまでロック待機状態になります。
プラス記号 (+) アンロックを実行せずに、指定されたロックの適用を試みます。これにより、現在のプロセスにより保持されているロックに、ロックを追加できます。このオプションの使用法の 1 つとして、ロック名の増分ロックの実行があります。
マイナス記号 (-) 指定されたロックをアンロックします。ロック名が 1 のロック・カウントを持つ場合、アンロックによりそのロックはロック・テーブルから削除されます。ロック名が 2 以上のロック・カウントを持つ場合、アンロックにより増分ロックの 1 つが削除されます (ロック・カウントをデクリメント)。既定では、このアンロックは排他の非エスカレート・ロックです。共有ロック/エスカレート・ロックの一方または両方を削除するには、対応する #locktype を指定する必要があります。

LOCK コマンドに、複数のコンマ区切りのロック引数が含まれる場合、各ロック引数は、独自のロック・オペレーション・インジケータを持つことができます。Caché はこれを、複数の非依存 LOCK コマンドとして解析します。

lockname

lockname はデータ・リソースのロックの名前であり、データ・リソースそのものではありません。つまり、プログラムは ^a(1) という名前のロックと、^a(1) という変数を競合なく使用できます。ロックとデータ・リソースの間の関係は、プログラミングの規約です。規約により、プロセスは対応するデータ・リソースを変更する前にロックを獲得する必要があります。

ロック名は、大文字と小文字を区別します。ロック名は、対応するローカル変数およびグローバル変数と同じ命名規則に従います。ロック名は、添え字付きでも添え字なしでもかまいません。ロックの添え字は、変数の添え字と同じ命名規則、最大長、およびレベル数を持ちます。Caché では、a、a(1)、A(1)、^a、^a(1,2)、^A(1,1,1) はすべて、有効で一意なロック名です。詳細は、"Caché ObjectScript の使用法" の "変数" の章を参照してください。

Note:

パフォーマンス上の理由から、可能な場合はいつでも、添え字を使用したロック名を指定することをお勧めします。例えば、^a よりも、^a(1) とします。添え字付きのロック名は、ドキュメントの例で使用されています。

ロック名は、ローカル、グローバルのどちらにもできます。A(1) などのロック名は、ローカル・ロック名です。これは、使用しているプロセスだけに適用されますが、ネームスペース全体に適用されます。キャレット記号 (^) で開始するロック名は、グローバル・ロック名です。このロックに対するマッピングは、対応するグローバルと同じマッピングに従います。つまり、プロセス全体に適用でき、同じリソースへのプロセスのアクセスを制御するということです ("Caché グローバルの使用法" の "グローバル構造" 参照)。

Note:

プロセス・プライベート・グローバル名は、ロック名として使用できません。プロセス・プライベート・グローバル名をロック名として使用しようとすると、エラーは発生しませんが、何も処理が実行されずに終了します。

ロック名はローカル、またはグローバル変数で、添え字付き、または添え字なしで表されます。また、暗黙のグローバル参照、または他のコンピュータのグローバルへの拡張参照も可能です ("Caché グローバルの使用法" の "グローバル構造" 参照)。

ロック名に対応するデータ・リソースが存在する必要はありません。例えば、同じ名前を持つグローバル変数の有無に関係なく、ロック名 ^a(1,2,3) をロックできます。ロックとデータ・リソースの間の関係は、合意された規約であるため、ロックはまったく異なる名前を持つデータ・リソースを保護するために使用できます。

locktype

適用または削除するロックのタイプを指定する文字コードです。locktype はオプションの引数です。locktype を省略する場合、ロック・タイプは既定では排他の非エスカレート・ロックになります。locktype を省略する場合、ポンド記号 (#) 接頭語を省略する必要があります。locktype を指定する場合、ロック・タイプの構文は、必須のポンド記号 (#) に、1 つ以上のロック・タイプ文字コードを囲む引用符が続きます。ロック・タイプ文字コードは順不同で指定でき、大文字と小文字の区別をしません。以下は、ロック・タイプ文字コードです。

  • S : 共有ロック

    同じリソース上で、競合しないロックを同時に保持するための複数のプロセスを許可します。例えば、2 つ (またはそれ以上) のプロセスは、同じリソース上で共有ロックを同時に保持しますが、排他ロックはリソースを 1 つのプロセスに制限します。既存の共有ロックがあると、他のすべてのプロセスの排他ロックは適用できなくなります。また既存の排他ロックがあると、他のプロセスの共有ロックは適用できなくなります。しかし、プロセスでまずリソースに共有ロックを適用し、その同じプロセスでリソースに排他ロックを適用することで、ロックを共有から排他にアップグレードできます。共有と排他ロックのカウントは、独立しています。したがって、そのようなリソースを解除するためには、排他ロックと共有ロックの両方を解除する必要があります。共有 (“S”) として指定されていないすべてのロックとアンロックのオペレーションは、排他が既定です。

    共有ロックはインクリメントである場合があります。つまり、同じリソースにおいて複数の共有ロックがプロセスによって発行される場合があります。ロックおよびアンロック時に、共有ロックをエスカレート (“SE”) として指定できます。共有ロックのアンロック時に、アンロックを即時 (“SI”) または遅延 (“SD”) として指定できます。エスカレート・ロックおよび非エスカレート・ロックのタイプにおけるインクリメント数と共に現在の共有ロックを表示するには、"Caché ObjectScript の使用法" の “Lock Management” の章で説明されているシステム全体のロック・テーブルを参照してください。

  • E : エスカレート・ロック

    ロック・テーブルをオーバーフローさせることなく、同時ロックの最大数を適用できます。既定では、ロックは非エスカレートです。ロックの適用時に、locktype “E” を使用して、そのロックをエスカレートとして指定できます。エスカレート・ロックのリリース時には、アンロック文で locktype “E” を指定する必要があります。排他ロックと共有 (“S”) ロックの両方をエスカレートと指定できます。

    一般に、同じ添え字レベルで多数の同時ロックを適用する場合に、エスカレート・ロックを使用することになります。例えば、LOCK +^mylock(1,1)#"E",+^mylock(1,2)#"E",+^mylock(1,3)#"E"... のようになります。

    同じロックを、非エスカレート・ロックおよびエスカレート・ロックとして同時に適用することができます。例えば、^mylock(1,1)^mylock(1,1)#"E" のようにすることができます。Caché は、ロック・テーブルで locktype “E” を指定して発行されたロックを個別にカウントします。ロック・テーブルでエスカレート・ロックおよび非エスカレートロックがどのように表示されるかについての詳細は、"Caché ObjectScript の使用法" の “ロック管理” の章を参照してください。

    添え字レベルの “E” ロックの数がしきい値に達すると、その添え字レベルで要求される次の “E” ロックは親ノード (次に高位の添え字レベル) を自動的にロックしようとします。不可能な場合は、エスカレーションは発生しません。親ノードのロックに成功すると、1 つの親ノードのロックが下位の添え字レベルのロックの数 + 1 に対応するロック・カウントで設定されます。下位の添え字レベルのロックは解除されます。その後の下位の添え字レベルへの “E” ロックの要求は、この親ノードのロックのロック・カウントをさらにインクリメントします。親ノードのロック・カウントを 0 にデクリメントし、下位の添え字レベルにエスカレーション解除するには、適用済みのすべての “E” ロックを解除する必要があります。ロックの既定のしきい値は 1000 ロックです。1001 番目のロックが要求されると、ロックのエスカレーションが発生します。

    ロックがエスカレートすると、ロック・オペレーションは、ロックされた特定のリソースではなく、適用されたロックの数のみを保持することに注意してください。そのため、ロックした同じリソースのロック解除に失敗すると、“E” ロックのカウントが同期されなくなります。

    以下の例では、プログラムがロックしきい値 + 1 の “E” ロックを適用すると、ロックのエスカレーションが発生します。この例では、ロックのエスカレーションにより、次に高い添え字レベルにおいてロックが適用されると同時に、下位の添え字レベルにおいてロックが解除されることを示しています。

    Main
      TSTART
      SET thold=$SYSTEM.SQL.GetLockThreshold()
      WRITE "lock escalation threshold is ",thold,!
      SET almost=thold-5
      FOR i=1:1:thold+5 { LOCK +dummy(1,i)#"E"
         IF i>almost {
           IF ^$LOCK("dummy(1,"_i_")","OWNER") '= "" {WRITE "lower level lock applied at ",i,"th lock ",! }
           ELSEIF ^$LOCK("dummy(1)","OWNER") '= ""   {WRITE "lock escalation",!
                                                      WRITE "higher level lock applied at ",i,"th lock ",!
                                                      QUIT }
           ELSE {WRITE "No locks applied",! }
         }
      }
      TCOMMIT

    ロック・エスカレーションに対してカウントされるのは “E” ロックだけであることに注意してください。以下の例では、既定 (非 “E”) のロックと “E” ロックの両方を同じ変数に設定します。ロックのエスカレーションは、変数における “E” ロックの合計数がロックしきい値に達した場合にのみ発生します。

    Main
      TSTART
      SET thold=$SYSTEM.SQL.GetLockThreshold()
      WRITE "lock escalation threshold is ",thold,!
      SET noE=17
      WRITE "setting ",noE," non-escalating locks",!
      FOR i=1:1:thold+noE { IF i < noE {LOCK +a(6,i)}
                      ELSE {LOCK +a(6,i)#"E"}
        IF ^$LOCK("a(6)","OWNER") '= "" {
           WRITE "lock escalation on lock a(6,",i,")",!
           QUIT }
      }
      TCOMMIT

    “E” ロックのロック解除は、上記の逆です。ロックがエスカレーションされている場合、子のレベルでのロック解除は、ゼロに達してロック解除されるまで親ノードのロックのロック・カウントをデクリメントします。これらのロック解除はカウントをデクリメントし、特定のロックとは一致しません。親ノードのロック・カウントが 0 に達すると、親ノードのロックが削除され、“E” ロックが下位の添え字レベルへとエスカレーション解除されます。それ以降の下位の添え字レベルのロックは、そのレベルで固有のロックを作成します。

    “E” locktype は、他の任意の locktype と組み合わせることができます。例えば、“SE”、“ED”、“EI”、“SED”、“SEI” などです。“I” locktype と組み合わせると、現在のトランザクションの最後ではなく、呼び出された直後に “E” ロックを解除できます。この “EI” locktype は、ロックがエスカレートされる状況を最低限に抑えることができます。

    通常、“E” ロックは、トランザクション内の SQL INSERTUPDATE、および DELETE 処理において自動的に適用されます。ただし、“E” ロックをサポートする SQL データ定義構造について固有の制限事項が存在します。詳細は、固有の SQL コマンドを参照してください。

  • I : 即時アンロック

    トランザクションの終了まで待つのではなく、ロックを即時に解除します。

    • 非増分 (ロック・カウント 1) ロックのアンロック時に “I” を指定すると、ロックは即時に解除されます。既定では、アンロックは非増分ロックを即時に解除しません。代わりに、非増分ロックをアンロックすると、Caché はそのロックを、トランザクションの終了までロック解除状態に維持します。“I” を指定すると、この既定の動作はオーバーライドされます。

    • 増分ロック (ロック・カウント > 1) のアンロック時に “I” を指定すると、増分ロックは即時に解除され、ロックカウントは 1 だけデクリメントされます。これは増分ロックの既定のアンロックと同じ動作です。

    “I” locktype は、トランザクション中にアンロックを実行する場合に使用します。これには、ロックがトランザクションの内部または外部のどちらで適用されたかに関係なく、Caché のアンロック動作に対して同じ効果があります。“I” locktype は、アンロックがトランザクションの外部で行われる場合は、オペレーションを実行しません。トランザクションの外部では、アンロックは必ず指定されたロックを即時に解除します。

    “I” は、アンロック・オペレーションにのみ指定できます。ロック・オペレーションには指定できません。“I” は、共有ロック (#"SI") または排他ロック (#"I") のアンロックに指定できます。Locktypes “I” および “D” は、相互排他的です。“IE” は、エスカレート・ロックの即時アンロックに使用できます。

    この即時アンロックを以下の例で示します。

      TSTART
      LOCK +^a(1)      // apply lock ^a(1)
      LOCK -^a(1)      // remove (unlock) ^a(1)
                       // An unlock without a locktype defers the unlock
                       // of a non-incremented lock to the end of the transaction.
      WRITE "Default unlock within a transaction.",!,"Go look at the Lock Table",!
      HANG 10          // This HANG allows you to view the current Lock Table
      LOCK +^a(1)      // reapply lock ^a(1)
      LOCK -^a(1)#"I"  // remove (unlock) lock ^a(1) immediately
                       // this removes ^a(1) from the lock table immediately
                       // without waiting for the end of the transaction
      WRITE "Immediate unlock within a transaction.",!,"Go look at the Lock Table",!
      HANG 10          // This HANG allows you to view the current Lock Table
                       // while still in the transaction
      TCOMMIT
  • D : 遅延アンロック

    アンロックされたロックをトランザクション中に解除するタイミングを制御します。アンロック状態は、そのロックの直前のアンロックの状態まで遅延されます。そのため、ロックをアンロックするときに locktype “D” を指定すると、そのトランザクション中のロックの履歴に応じて、即時アンロックになるか、またはトランザクションの終わりまでロック解除状態になるかのいずれかの結果になります。複数回ロック/アンロックされたロックの動作は、現在のトランザクション中に 1 回のみロックされたロックの動作とは異なります。

    “D” アンロックは、ロックを解除するアンロック (ロック・カウント 1) のみに有効であり、ロックをデクリメントするアンロック (ロック・カウント > 1) には無効です。ロックをデクリメントするアンロックは、常に即時に解除されます。

    “D” は、アンロック・オペレーションにのみ指定できます。“D” は、共有ロック (#"SD") または排他ロック (#"D") に指定できます。“D” は、エスカレート (“E”) ロックに指定できますが、当然ながらアンロックもエスカレート (“ED”) として指定する必要があります。ロック・タイプ “D” と “I” は、相互排他的です。

    トランザクション内でのこの “D” アンロックの使用を以下の例に示します。HANG コマンドを実行すると、ロック・テーブルにあるロックの ModeCount を確認する時間を取ることができます。

    ロックが現在のトランザクション中に 1 回のみ適用された場合、“D” はロックを即時に解除します。これは “I” の振る舞いと同じです。詳細は、以下の例を参照してください。

      TSTART
      LOCK +^a(1)      // Lock Table ModeCount: Exclusive
      LOCK -^a(1)#"D"  // Lock Table ModeCount: null (immediate unlock)
      HANG 10
      TCOMMIT

    現在のトランザクション中にロックが複数回適用された場合、“D” アンロックは直前のアンロック状態に戻します。

    • 最後のアンロックが標準アンロックであった場合、“D” アンロックは、その直前のアンロックの動作に戻します。つまり、トランザクションの終了までアンロックを遅延します。詳細は、以下の例を参照してください。

        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)      // Lock Table ModeCount: Exclusive
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive->Delock
           WRITE "2nd unlock",! HANG 5
        TCOMMIT
        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)      // Lock Table ModeCount: Exclusive->Delock
           WRITE "1st unlock",! HANG 5
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive->Delock
           WRITE "2nd unlock",! HANG 5
        TCOMMIT
        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"I"  // Lock Table ModeCount: Exclusive/2
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)      // Lock Table ModeCount: Exclusive
           WRITE "2nd unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive->Delock
           WRITE "3rd unlock",! HANG 5
        TCOMMIT
    • 最後のアンロックが “I” アンロックであった場合、“D” アンロックは、その直前のアンロックの動作に戻します。つまり、ロックを即時にアンロックします。詳細は、以下の例を参照してください。

        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"I"  // Lock Table ModeCount: null (immediate unlock)
           WRITE "1st unlock",! HANG 5
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"D"  // Lock Table ModeCount: null (immediate unlock)
           WRITE "2nd unlock",! HANG 5
        TCOMMIT
        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"I"  // Lock Table ModeCount: Exclusive
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: null (immediate unlock)
           WRITE "2nd unlock",! HANG 5
        TCOMMIT
    • 最後のアンロックが “D” アンロックだった場合、“D” アンロックは直前の非 “D” ロックの動作に従います。

        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: null (immediate unlock)
           WRITE "2nd unlock",! HANG 5
        TCOMMIT
        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)      // Lock Table ModeCount: Exclusive/2
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive
           WRITE "2nd unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive->Delock
           WRITE "3rd unlock",! HANG 5
        TCOMMIT
        TSTART
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK +^a(1)      // Lock Table ModeCount: Exclusive
        LOCK -^a(1)#"I"  // Lock Table ModeCount: Exclusive/2
           WRITE "1st unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: Exclusive
           WRITE "2nd unlock",! HANG 5
        LOCK -^a(1)#"D"  // Lock Table ModeCount: null (immediate unlock)
           WRITE "3rd unlock",! HANG 5
        TCOMMIT

timeout

タイムアウト前に、ロックを待機する時間 (秒数) です。timeout はオプションの引数です。省略された場合、LOCK コマンドはリソースがロック可能になるまで無制限に待機します。ロックが適用できない場合、プロセスは停止します。timeout の構文には、必須のコロン (:) が最初にあり、その後に整数値や、整数値に評価される式が続きます。ゼロの値は、タイムアウトの前に 1 つのロックの試みを許可します。負の数は、ゼロと同様です。

通常、ロック要求が指定ロックを取得する (保持する) のを妨げる競合ロックが別プロセスに存在する場合、ロックは待機します。ロック要求は、ロックが解除されて競合が解決されるか、またはロック要求がタイムアウトになるまで待機します。プロセスを終了しても保留中のロック要求が終了します (削除されます)。ロックの競合は、別プロセスが保持するのと同じロックをあるプロセスが要求する場合だけでなく、さまざまな状況によって発生する場合があります。ロックの競合およびロック要求の待機状態の詳細は、"Caché ObjectScript の使用法" の “ロック管理” の章を参照してください。

timeout を使用し、ロックに成功した場合、Caché は特殊変数 $TEST を 1 (TRUE) に設定します。タイムアウト時間内にロックを適用できなかった場合、Caché は $TEST を 0 (FALSE) に設定します。timeout を指定せずにロック要求を出した場合、$TEST の現在値には何の影響を及ぼしません。$TEST は、ユーザが設定することもできます。また、JOBOPEN、または READ のタイムアウトで設定されることもあります。

以下の例では、ロックをロック名 ^abc(1,1) に適用し、プロセスにより保持されている既存のすべてのロックをアンロックします。

  LOCK ^abc(1,1)

このコマンドは、排他ロックを要求します。他のプロセスは、このリソース上のロックを同時に保持することができません。他のプロセスが既にこのリソース上のロックを保持している場合 (排他、または共有)、この例では、ロックが解除されるまで待機する必要があります。プロセスを停止しながら、無制限に待機できます。この状態を避けるため、タイムアウト値を指定することを強くお勧めします。

  LOCK ^abc(1,1):10

LOCK により、コンマ区切りリストの lockname 引数を複数指定する場合、各 lockname リソースは専用の timeout (括弧なしの構文) を備えるか、または、指定した lockname リソースすべてが単一の timeout (括弧付きの構文) を共有することもできます。

  • 括弧なし:各 lockname 引数には固有の timeout を指定できます。Caché はこれを複数の独立した LOCK コマンドとして解析するので、ロック引数の timeout は他のロック引数に影響を与えません。ロック引数は厳密に左から右の順で解析され、各ロック要求は、次のロック要求が試される前に、完了するかまたはタイムアウトします。

  • 括弧付き:すべての lockname 引数で timeout を共有します。LOCK は、タイムアウト時間内にすべてのロック (またはアンロック) を正常に適用する必要があります。すべてのロックが成功する前にタイムアウト時間が経過した場合、LOCK コマンドで指定されたどのロック・オペレーションも実行されず、制御はプロセスに戻ります。

Caché は、厳密に左から右の順に複数のオペレーションを実行します。したがって、括弧なしの LOCK 構文では、$TEST の値は複数の lockname ロック要求の最後 (右端) の結果を示しています。

以下の例では、現在のプロセスは ^a(1) を、別のプロセスにより排他的にロックされているためロックできません。これらの例では、指定されたロックへの適用を 1 回試みることになる、タイムアウト 0 を使用しています。

最初の例は、^x(1) および ^z(1) をロックします。^z(1) がタイムアウト前に成功したので、これは $TEST=1 を設定します。

  LOCK +^x(1):0,+^a(1):0,+^z(1):0

2 番目の例は、^x(1) および ^z(1) をロックします。^z(0) がタイムアウトしたので、これは $TEST=1 を設定します。^z(1) はタイムアウトを指定していなかったため、$TEST に効果はありません。

  LOCK +^x(1):0,+^a(1):0,+^z(1):0

3 番目の例は、括弧で囲まれたロックのリストがアトミック (全か無か) オペレーションであるため、ロックを適用しません。^a(1) がタイムアウトしたので、これは $TEST=0 を設定します。

  LOCK +(^x(1),^a(1),^z(1)):0

ロック・テーブルを使用したシステム全体のロックの表示および削除

Caché は、システム全体のロック・テーブルを保持しています。このテーブルには、その時点で有効なロックとそれを適用しているプロセスがすべて記録されています。システム管理者は、"Caché ObjectScript の使用法" の “ロック管理” の章に記載されているように、管理ポータル インタフェースまたは ^LOCKTAB ユーティリティを使用して、ロック・テーブルで既存のロックを表示したり、選択されたロックを削除したりできます。%SYS.LockQueryOpens in a new tab クラスを使用して、ロック・テーブル情報を読み取ることもできます。%SYS ネームスペースから SYS.LockOpens in a new tab クラスを使用することで、ロック・テーブルを管理できます。

管理ポータルを使用することで、システム全体で保持されているロックおよび保留中のロック要求を表示できます。管理ポータルに移動して、[システム処理] を選択し、[ロック] を選択して、[ロック表示] (システム, ロック表示) を選択します。[ロック表示] テーブルの詳細は、"Caché ObjectScript の使用法" の “ロック管理” の章を参照してください。

管理ポータルを使用することで、システムにおいて現在保持されているロックを削除できます。管理ポータルに移動して、[システム処理] を選択し、[ロック] を選択して、[ロックの管理] (システム, ロックの管理) を選択します。任意のプロセス ([所有者]) について、“[削除]” または “[プロセスが保持するすべてのロックを削除]” をクリックします。

ロックを削除すると、そのロックのすべての形式 (ロックのすべての増分レベル、ロックのすべての排他バージョン、排他エスカレート・バージョン、および共有バージョン) が解除されます。ロックを削除すると、そのロック・キューで待機している次のロックが直ちに適用されます。

ロックは、SYS.Lock.DeleteOneLock()Opens in a new tab および SYS.Lock.DeleteAllLocks()Opens in a new tab メソッドを使用しても削除できます。

ロックの削除には、WRITE 権限が必要です。ロックの削除は、監査データベースに記録されます (有効になっている場合) 。cconsole.log には記録されません。

増分ロックおよびアンロック

増分ロックでは、同じロックを複数回適用できます。つまりロックをインクリメントします。増分ロックのロック・カウントは > 1 です。その後、プロセスはこのロック・カウントをインクリメント、またはデクリメントすることができます。ロック・カウントが 0 までデクリメントされると、ロックは解除されます。ロック・カウントが 0 までデクリメントされるまで、他のプロセスはロックを獲得できません。ロック・テーブルは、排他ロックと共有ロック、およびその各タイプのエスカレート・ロックと非エスカレート・ロックの、個別のロック・カウントを維持します。最大増分ロック・カウントは 32,766 です。この最大ロック・カウントを超過しようとすると、<MAX LOCKS> エラーになります。

ロックは以下のようにインクリメントできます。

  • プラス記号 : 同じロック名に対する複数のロック・オペレーションを、プラス記号ロック・オペレーション・インジケータを付けて指定します。例 : LOCK +^a(1) LOCK +^a(1) LOCK +^a(1)、または LOCK +^a(1),+^a(1),+^a(1)、または LOCK +(^a(1),^a(1),^a(1))。このすべては、ロック・テーブル ModeCount の Exclusive/3 という結果になります。ロックを増分するためには、プラス記号を使用することをお勧めします。

  • 記号なし : 複数のロックを実行するアトミック・オペレーションを指定することで、プラス記号ロック・オペレーション・インジケータを使用しなくても、ロックを増分することは可能です。例えば、LOCK (^a(1),^a(1),^a(1)) は、既存のすべてのロックをアンロックして、^a(1) を 3 回増分ロックします。これも、ロック・テーブル ModeCount の Exclusive/3 という結果になります。この構文は機能しますが、お勧めしません。

トランザクション中でないときに増分ロックをアンロックしても、ロック・カウントがデクリメントされるだけです。トランザクション中に増分ロックをアンロックした場合には、以下のデフォルトの動作になります。

  • アンロックのデクリメント:各デクリメント・アンロックは、ロック・カウントが 1 になるまで増分アンロックを即時に解除します。既定では、最終アンロックは、ロックをロック解除状態にして、トランザクションの終了までロックの解除を遅延します。オペレーションがアトミックであるかどうかに関係なく、マイナス記号ロック・オペレーション・インジケータを使用してロック解除するときは、必ずこのようになります。例 : LOCK -^a(1) LOCK -^a(1) LOCK -^a(1)、または LOCK -^a(1),-^a(1),-^a(1)、または LOCK -(^a(1),^a(1),^a(1))。このすべてで、ロック・テーブルの先頭は ModeCount の Exclusive/3、末尾は Exclusive->Delock となります。

  • 既存のリソースのアンロック:既存のすべてのリソースをアンロックするオペレーションは、トランザクションの終了までに、増分ロックを即時にロック解除状態にします。例えば、LOCK x(3) (ロック・オペレーション・インジケータなしのロック) または引数なし LOCK では、増分ロックでロック・テーブルの先頭は ModeCount の Exclusive/3、末尾は Exclusive/3->Delock となる効果があります。

同じロックでも、排他ロック、共有ロック、排他エスカレート・ロック、および共有エスカレート・ロックには個別のロック・カウントが維持されます。以下の例では、最初のアンロックで、ロック ^a(1) の 4 つの個別ロック・カウントが 1 だけデクリメントされます。2 番目のアンロックでは、4 つすべての ^a(1) ロックでそれらを削除するように指定する必要があります。HANG コマンドを実行すると、ロック・テーブルにあるロックの ModeCount を確認する時間を取ることができます。

   LOCK +(^a(1),^a(1)#"E",^a(1)#"S",^a(1)#"SE")
   LOCK +(^a(1),^a(1)#"E",^a(1)#"S",^a(1)#"SE")
   HANG 10
   LOCK -(^a(1),^a(1)#"E",^a(1)#"S",^a(1)#"SE")
   HANG 10
   LOCK -(^a(1),^a(1)#"E",^a(1)#"S",^a(1)#"SE")

現在適用されているロックがないロック名をアンロックしようとしても、オペレーションは実行されず、エラーは返されません。

自動アンロック

プロセスが終了すると、Caché は引数なしの暗黙の LOCK を実行して、そのプロセスが適用していたロックをすべて消去します。これにより保持されていたロックとロック待機要求の両方が削除されます。

グローバル変数のロック

ロックは、同時に同じ変数にアクセスする可能性のある、複数のプロセスの動作の同期をとるために、グローバル変数で使用されるのが一般的です。グローバル変数はディスクに存在し、すべてのプロセスに対して利用可能であるという点で、ローカル変数とは異なります。そのため、2 つのプロセスが、同じグローバル変数に同時に書き込みを行う可能性があります。実際には、Caché は、更新を 1 つずつ処理します。したがって、ある更新によって、その次に更新が予定されていたものが上書きされ、実質的に、破棄されたりすることがあります。

グローバル・ロック名は ^ 文字で開始します。

グローバル変数のロックを分かりやすく説明するために、2 人のデータ入力者が、新しく入学した学生のレコードを追加するために、同時に同じ学生入学アプリケーションを実行している場合を考えてみましょう。レコードは、^ student という名前のグローバル配列に格納されています。学生 1 人 1 人に一意のレコードを確保するために、アプリケーションでは、学生が追加されるたびに、グローバル変数 ^ Index がインクリメントされます。各学生レコードが配列の一意の場所に追加されること、およびある学生レコードが他のレコードを上書きしないことを保証するために、アプリケーションには LOCK コマンドが含まれています。

このアプリケーションに関連するコードを以下に示します。この場合 LOCK はグローバル配列 ^student ではなく、グローバル変数 ^index を制御します。^index は、2 つのプロセスによって共用されるスクラッチ・グローバルです。プロセスは ^index をロックし、その現在の値を更新 (SET ^index=^index+1) して初めて、配列にレコードの書き込みができます。他のプロセスが既にコードのこのセクションに入っている場合は、^index がロックされているので、そのプロセスが (引数なしの LOCK コマンドで) ロックを解除するまで、次のプロセスは待機しなければなりません。

 READ !,"Last name: ",!,lname QUIT:lname=""  SET lname=lname_"," 
 READ !,"First name: ",!,fname QUIT:fname=""  SET fname=fname_"," 
 READ !,"Middle initial: ",!,minit QUIT:minit=""  SET minit=minit_":" 
 READ !,"Student ID Number: ",!,sid QUIT:sid=""
 SET rec = lname_fname_minit_sid
 LOCK ^index
 SET ^index = ^index + 1
 SET ^student(^index)=rec
 LOCK

以下の例では、前述の例を書き直し、 ^student 配列に追加されるノードにロックを設定するようにしています。関連部分のコードだけを示します。この場合、変数 ^index は、新しい学生レコードが追加された後、更新されます。レコードを追加する次のプロセスは、更新された index 値を使用して、現在の配列ノードに書き込みを行います。

 LOCK ^student(^index)
 SET ^student(^index) = rec
 SET ^index = ^index + 1
 LOCK  /* release all locks */

配列ノードのロックの位置は、トップ・レベルのグローバルがマップされている位置になることに注意してください。Caché は、ロックの位置の決定時に添え字を無視します。したがって、^student(name) のデータが格納されている場所に関係なく、^student(name) は ^student のネームスペースにマップされます。

ネットワークにおけるロック

ネットワーク・システムでは、1 つ、または複数のサーバがグローバル変数のロックを解決する役割を果たすことができます。

LOCK コマンドは、最大 255 までの、任意の数のサーバで使用できます。リモート・サーバ・システム上のクライアント・ジョブにより保持されるリモート・ロックは、クライアント・ジョブを削除するために ^RESJOB ユーティリティを呼び出すときに解除されます。

ローカル変数ロック

ローカル (^ 記号が付いていない) 変数に対する LOCK の振る舞いは、Caché および Open M [DTM] 上ですべて同じです。Config.MiscellaneousOpens in a new tab クラスには、ZaModeOpens in a new tab プロパティがあります。このプロパティを使用して、従来のロック・コマンド DSM-11 ZALLOCATE (ZA) および ZDEALLOCATE (ZD) との互換性のためにシステム全体にロック・モードを設定できます。

Open M [DTM] では、ローカル・ロックは、最初の文字にかかわらず、常にマネージャのデータセットで取得されます。Caché に移されたアプリケーションが、% 文字で始まらないローカル・ロックを使用する場合、アプリケーションが同じローカルの % 以外のロック名を異なるデータセットで使用すると、デッドロック状態になる可能性があります。ロックは同じアイテムに解決されるために、衝突します。これが階層的ロック・システムの一部である場合は、デッドロックがアプリケーションを停止させる可能性もあります。

現在の振る舞いは以下のとおりです。

  • 特定のネームスペースのコンテキストで取得されるローカル ( ^ が付いていない) ・ロックは、ローカル・マシンのマネージャのデータセットから取得されます。これは、既定のネームスペースが、明示的なネームスペースであるか、またはネームスペースの明示的な参照によるためです。この場合、グローバルに対する既定のマッピングがローカル・データセットか、リモート・データセットかは関係ありません。

  • 暗黙のネームスペースのコンテキストで、またはローカル・マシンの暗黙のネームスペースへの明示的な参照を通じて取得されたローカル ( ^ が付いていない) ・ロックは、ローカル・マシンのマネージャのデータセットを使用して取得されます。暗黙のネームスペースは、"^^dir" のように 2 つのキャレット文字が先行するディレクトリ・パスです。

明示的、または暗黙のネームスペースの参照に関する詳細は、"Caché グローバルの使用法" の "グローバル構造" を参照してください。

関連項目

FeedbackOpens in a new tab