Adobe ColdFusion 8

Using the cflock tag

The cflock tag ensures that concurrently executing requests do not run the same section of code simultaneously and thus manipulate shared data structures, files, or CFX tags inconsistently. It is important to remember that cflock protects code sections that access or set data, not the variables themselves.

You protect access to code by surrounding it in a cflock tag; for example:

<cflock scope="Application" timeout="10" type="Exclusive">
    <cfif not IsDefined("Application.number")>
        <cfset Application.number = 1>
    </cfif>
</cflock>

Lock types

The cflock tag offers two modes of locking, specified by the type attribute:

Exclusive locks (the default lock type): Allow only one request to process the locked code. No other requests can run code inside the tag while a request has an exclusive lock.

Enclose all code that creates or modifies session, application, or server variables in exclusive cflock tags.

Read-only locks: Allow multiple requests to execute concurrently if no exclusive locks with the same scope or name are executing. No requests can run code inside the tag while a request has an exclusive lock.

Enclose code that only reads or tests session, application, or server variables in read-only cflock tags. You specify a read-only lock by setting the type="readOnly" attribute in the cflock tag, for example:

<cflock scope="Application" timeout="10" type="readOnly">
    <cfif IsDefined("Application.dailyMessage")>
        <cfoutput>#Application.dailyMessage#<br></cfoutput>
    </cfif>
</cflock>

Although ColdFusion does not prevent you from setting shared variables inside read-only lock tag, doing so loses the advantages of locking. As a result, you must be careful not to set any session, application, or server variables inside a read-only cflock tag body.

Note: You cannot upgrade or downgrade a lock from one type to another. In other words, do not nest an exclusive lock in a read-only lock of the same name or scope; the exclusive lock will always time out. Also, do not nest a read-only lock inside an exclusive lock with the same name or scope; doing so has no effect.

Lock scopes and names

The cflock tag prevents simultaneous access to sections of code, not to variables. If you have two sections of code that access the same variable, they must be synchronized to prevent them from running simultaneously. You do this by identifying the locks with the same scope or name attributes.

Note: ColdFusion does not require you to identify exclusive locks. If you omit the identifier, the lock is anonymous and you cannot synchronize the code in the cflock tag block with any other code. Anonymous locks do not cause errors when they protect a resource that is used in a single code block, but they are bad programming practice. You must always identify read-only locks.

Controlling access to data with the scope attribute

When the code that you are locking accesses session, application, or server variables, synchronize access by using the cflock scope attribute.

You can set the attribute to any of the following values:

Scope

Meaning

Server

All code sections with this attribute on the server share a single lock.

Application

All code sections with this attribute in the same application share a single lock.

Session

All code sections with this attribute that run in the same session of an application share a single lock.

Request

All code sections with this attribute that run in the same request share a single lock. You use this scope only if your application uses the cfthread tag to create multiple threads in a single request. Locking the Request scope also locks access to Variables scope data. For more information on locking the Request scrope, see Locking thread data and resource access.

If multiple code sections share a lock, the following rules apply:

  • When code is running in a cflock tag block with the type attribute set to Exclusive, code in cflock tag blocks with the same scope attribute is not allowed to run. They wait until the code with the exclusive lock completes.
  • When code in a cflock tag block with the type readOnly is running, code in other cflock tag blocks with the same scope attribute and the readOnly type attribute can run, but any blocks with the same scope attribute and an Exclusive type cannot run and must wait until all code with the read-only lock completes. However, if a read-only lock is active and code with an exclusive lock with the same scope or name is waiting to execute, read-only requests using the same scope or name that are made after the exclusive request is queued must wait until code with the exclusive lock executes and completes.

Controlling locking access to files and CFX tags with the name attribute

The cflock name attribute provides a second way to identify locks. Use this attribute when you use locks to protect code that manges file access or calls non-thread-safe CFX code.

When you use the name attribute, specify the same name for each section of code that accesses a specific file or a specific CFX tag.

Controlling and minimizing lock time-outs

You must include a timeout attribute in your cflock tag. The timeout attribute specifies the maximum time, in seconds, to wait to obtain the lock if it is not available. By default, if the lock does not become available within the time-out period, ColdFusion generates a Lock type exception error, which you can handle using cftry and cfcatch tags.

If you set the cflock throwOnTimeout attribute to No, processing continues after the time-out at the line after the </cflock> end tag. Code in the cflock tag body does not run if the time-out occurs before ColdFusion can acquire the lock. Therefore, never use the throwOnTimeout attribute for CFML that must run.

Normally, it does not take more than a few seconds to obtain a lock. Very large time-outs can block request threads for long periods of time and radically decrease throughput. Always use the smallest time-out value that does not result in a significant number of time-outs.

To prevent unnecessary time-outs, lock the minimum amount of code possible. Whenever possible, lock only code that sets or reads variables, not business logic or database queries. One useful technique is to do the following:

  1. Perform a time-consuming activity outside of a cflock tag
  2. Assign the result to a Variables scope variable
  3. Assign the Variables scope variable's value to a shared scope variable inside a cflock block.

For example, if you want to assign the results of a query to a session variable, first get the query results using a Variables scope variable in unlocked code. Then, assign the query results to a session variable inside a locked code section. The following code shows this technique:

<cfquery name="Variables.qUser" datasource="#request.dsn#">
    SELECT FirstName, LastName
    FROM Users
    WHERE UserID = #request.UserID#
</cfquery>
<cflock scope="Session" timeout="5" type="exclusive">
    <cfset Session.qUser = Variables.qUser>
</cflock>