cflock

説明

共有データの整合性を維持します。次のロックを適用します。

  • Exclusive: 本文内の CFML 構文に対してシングルスレッドのアクセスを行うことができます。このタグの本文は、一度に 1 つのリクエストでしか実行できません。あるリクエストが排他的ロックをかけている間は、タグ内のコードを他のリクエストが開始することはできません。ColdFusion は、排他的ロックを早い者勝ちで適用します。

  • Read-only: 複数のリクエストがタグ本文内の CFML 構文に同時にアクセスできます。読み取り専用ロックは、共有データを読み取る場合にのみ使用し、共有データを修正する場合には使用しないでください。あるリクエストが共有データの排他的ロックを取得している場合、新規リクエストはその排他的ロックが解除されるのを待機することになります。

シンタックス

<cflock  
    timeout = "time-out in seconds" 
    name = "lock name" 
    scope = "Application|Server|Session|Request" 
    throwOnTimeout = "yes|no" 
    type = "readOnly|exclusive">  
    <!--- CFML to be synchronized. --->  
</cflock>
注意: このタグの属性は attributeCollection 属性で指定でき、その値は構造体になります。attributeCollection 属性で構造体の名前を指定し、タグの属性名を構造体のキーとして使用します。

関連項目

cfapplicationcfassociatecfmessagebox『ColdFusion アプリケーションの開発』のUsing Persistent Data and Locking

履歴

ColdFusion 8: scope 属性の値として Request が追加されました。

属性

属性

必須 / オプション

デフォルト

説明

timeout

必須

ロックを取得するときに待機する最大時間を秒単位で指定します。ロックが取得されると、タグの実行は継続します。ロックを取得できない場合の動作は、throwOnTimeout 属性の値によって異なります。timeout="0" を指定した場合、タイムアウトは ColdFusion Administrator の [設定] ページでの "リクエストタイムアウト x" の設定 (この設定が有効なとき) により決まります。ただし、この設定が有効でない場合に timeout="0" を指定すると、ColdFusion はロックを取得するまで無限に待機することになります。

name

オプション

ロック名です。scope 属性と併用することはできません。特定の名前を持つ cflock タグ内のコードを実行できるのは、一度に 1 つのリクエストだけに限られます。空の文字列は指定できません。

アプリケーションのさまざまな部分からのリソースへのアクセスを同期化できます。ロック名は、ColdFusion サーバーに対してグローバルです。ロック名は、アプリケーションおよびユーザーセッション間で共有できますが、クラスタ化された複数のサーバー間にわたって共有することはできません。

scope

オプション

ロックのスコープです。name 属性とは排他の関係です。指定のスコープ内では、一度に 1 つのリクエストだけがこのタグ内のコード (または同じロックスコープの別の cflock タグ内のコード) を実行できます。

  • Application

  • Request

  • Server

  • Session

throwOnTimeout

オプション

yes

タイムアウト条件を処理する方法です。

  • yes: タイムアウト時に例外が生成されます。

  • no: このタグの時間を経過しても実行が継続されます。

type

オプション

exclusive

  • readOnly: 複数のリクエストで共有データを読み取ることができます。

  • exclusive: 1 つのリクエストで共有データを読み書きできます。

注意: 共有データの構造体、ファイル、および CFX を更新するコードのスコープを制限してください。排他的ロックはこれらの更新の整合性を確保するために必要ですが、読み取り専用ロックのほうが高速に処理されます。パフォーマンスを重視するアプリケーションの場合は、共有データを読み取るときなどは、できるかぎり排他的ロックではなく読み取り専用ロックを使用してください。

使用方法

ColdFusion はマルチスレッドサーバーです。したがって、一度に複数のページリクエストを処理することができます。cflock タグは、次の目的で使用します。

  • 同時に実行されるリクエストでの共有データやオブジェクトに対する修正が、整然とした順序で行われるようにします。

  • ファイル操作の構造をこのタグで囲み、ファイルの更新時に他のアプリケーションやタグがそのファイルを書き込み用に開いていることがないようにします。

  • CFX 呼び出しをこのタグで囲み、スレッドセーフな方法で実装されていない CFX を ColdFusion で安全に呼び出せるようにします(これは、C++ で開発された CFX にのみ該当します)。

    ColdFusion を安全に動作させるには、共有 (グローバル) データ構造体の管理と操作を行う C++ CFX がスレッドセーフでなければなりません。しかし、これには高度な知識が必要です。CFML カスタムタグラッパーで CFX を囲むと、呼び出しをスレッドセーフにすることができます。

    共有スコープで変数の表示、設定、更新を行う場合は、scope 属性を使用して Server、Application、Session のいずれかを特定してください。

デッドロック

デッドロックとは、ページ内のロックされた部分のコードをどのリクエストも実行できない状態です。デッドロックが発生すると、どのユーザーもロックを解除できなくなります。なぜなら、ロックタイムアウトによってデッドロックが解消されるまで、ページ内の保護されたセクションへのリクエストはすべて拒否されるからです。

cflock タグでは、カーネルレベルの同期オブジェクトを使用します。このオブジェクトは、それを使用しているスレッドがタイムアウトするか異常終了した時点で、自動的に解放されます。したがって、ColdFusion が cflock タグの処理中に永遠にデッドロックされることはありません。しかし、タイムアウト時間が長すぎると、リクエストスレッドが長時間にわたってブロックされ、スループットが急激に低下する可能性があります。これを避けるには、常に最低限のタイムアウト値を使用してください。

リクエストスレッドがブロックされる別の原因としては、cflock タグのネスト構造やロック名が一貫していないことが考えられます。ロックをネストする場合は、ロックされた変数にアクセスするコードが、一貫して同じ順序で cflock タグをネストする必要があります。そうしないと、デッドロックが発生する可能性があります。

次に、デッドロックが発生する例を示します。

ユーザーが 2 人の場合のデッドロックの例

ユーザー 1

ユーザー 2

Session スコープをロックします。

Application スコープをロックします。

デッドロック : Application スコープをロックしようとしますが、Application スコープはユーザー 2 によって既にロックされています。

デッドロック : Session スコープをロックしようとしますが、Session スコープはユーザー 1 によって既にロックされています。

読み取りロックの中に排他的ロックをネストしようとすると、次のようなデッドロックが発生する可能性があります。

ユーザーが 1 人の場合のデッドロックの例

ユーザー 1

Session スコープを読み取りロックでロックします。

Session スコープを排他的ロックでロックしようとします。

デッドロック : Session スコープは既に読み取りロックでロックされているので、Session スコープを排他的ロックでロックすることはできません。

次のコードは、この事例を示しています。

<cflock timeout = "60" scope = "SESSION" type = "readOnly"> 
    ............... 
    <cflock timeout = "60" scope = "SESSION" type = "Exclusive"> 
    ......... 
    </cflock> 
</cflock>

デッドロックを避けるには、ロックをネストするすべてのコードが、一貫した順序でネストし、一貫した名前を付ける必要があります。Server、Application、および Session スコープへのアクセスをロックする必要がある場合は、次の順序に従ってください。

  1. Session スコープをロックします。cflock タグ内で、scope = "session" を指定します。

  2. Application スコープをロックします。cflock タグで scope = "Application" を指定します。

  3. Server スコープをロックします。cflock タグ内で、scope = "server" を指定します。

  4. Server スコープのロックを解除します。

  5. Application スコープのロックを解除します。

  6. Session スコープのロックを解除します。

    注意: スコープをロックする必要がない場合は、そのスコープのロックとロック解除の手順を省略できます。たとえば、Server スコープをロックする必要がない場合は、手順 3 と 4 を省略できます。名前付きロックにも同様のルールが適用されます。

    詳細については、次の資料を参照してください。

<!---  
This example shows how cflock can guarantee consistency of data updates to variables in the 
    Application, Server, and Session scopes. ---> 
 
<!--- Copy the following code into an Application.cfm file in the  
    application root directory. ---> 
<!----------------   Beginning of Application.cfm code   ---------------> 
<!--- cfapplication defines scoping for a ColdFusion application and enables or disables 
    storing of application and session variables. Put this tag in a special file called 
    Application.cfm. It is run before any other ColdFusion page in its directory. ---> 
 
<!--- Enable session management for this application. ---> 
<cfapplication name = "ETurtle"  
    sessionTimeout = #CreateTimeSpan(0,0, 0, 60)#  
    sessionManagement = "yes"> 
 
<!--- Initialize session and application variables used by E-Turtleneck. Use session scope 
    for the session variables. --->  
<cflock scope = "Session"  
    timeout = "30" type = "Exclusive"> 
    <cfif NOT IsDefined("session.size")> 
        <cfset session.size = ""> 
    </cfif> 
    <cfif NOT IsDefined("session.color")> 
        <cfset session.color = ""> 
    </cfif> 
</cflock> 
 
<!--- Use an application lock for the application-wide variable that keeps track of the 
    number of turtlenecks sold. For a more efficient, but more complex, way of handling 
    Application scope locking, see the "Developing ColdFusion Applications"---> 
<cflock scope = "Application" timeout = "30" type = "Exclusive"> 
    <cfif NOT IsDefined("application.number")> 
        <cfset application.number = 0> 
    </cfif> 
</cflock> 
 
<!----------------------- End of Application.cfm -----------------------> 
 
<h3>cflock Example</h3> 
 
<cfif IsDefined("form.submit")> 
<!--- The form has been submitted; process the request. ---> 
    <cfoutput> 
        Thanks for shopping E-Turtleneck. You chose size <b>#form.size#</b>,  
        color <b>#form.color#</b>.<br><br> 
    </cfoutput> 
 
<!--- Lock the code that assigns values to session variables. ---->  
    <cflock scope = "Session" timeout = "30" type = "Exclusive"> 
        <cfparam name = session.size Default = #form.size#> 
        <cfparam name = session.color Default = #form.color#> 
    </cflock> 
 
<!---- Lock the code that updates the Application scope number of turtlenecks sold. --->  
    <cflock scope = "Application" timeout = "30" type = "Exclusive"> 
        <cfset application.number = application.number + 1> 
    <cfoutput> 
        E-Turtleneck has now sold #application.number# turtlenecks! 
    </cfoutput> 
    </cflock> 
 
<cfelse> 
<!--- Show the form only if it has not been submitted. ---> 
    <cflock scope = "Application" timeout = "30" type = "Readonly"> 
        <cfoutput> 
            E-Turtleneck has sold #application.number# turtlenecks to date. 
        </cfoutput> 
    </cflock> 
 
    <form method="post" action="cflocktest.cfm"> 
        <p>Congratulations! You selected the most comfortable turtleneck in the world. 
        Please select color and size.</p>  
        <table cellspacing = "2" cellpadding = "2" border = "0"> 
            <tr> 
                <td>Select a color.</td> 
                <td><select type = "Text" name = "color"> 
                        <option>red 
                        <option>white 
                        <option>blue 
                        <option>turquoise 
                        <option>black 
                        <option>forest green 
                    </select> 
                </td> 
            </tr> 
            <tr> 
                <td>Select a size.</td> 
                <td><select type = "Text" name = "size" > 
                        <option>XXsmall 
                        <option>Xsmall 
                        <option>small 
                        <option>medium 
                        <option>large 
                        <option>Xlarge 
                    </select> 
                </td> 
            </tr> 
            <tr> 
                <td>Press Submit when you are finished making your selection.</td> 
                <td><input type = "Submit" name = "submit" value = "Submit"> </td> 
            </tr> 
        </table> 
    </form> 
</cfif>