Locking Code with cflock

The cflock tag controls simultaneous access to ColdFusion code. The cflock tag enables you to:

Failure to use cflock in these circumstances can result in data corruption and can result in hanging the ColdFusion Server. Symptoms of this corruption include the following:

Using cflock

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>

How cflock works

ColdFusion Server is a multithreaded Web application server that can process multiple page requests at a time. As a result, the server can attempt to access the same information simultaneously as the result of two or more requests. While it is safe to read data simultaneously, attempting to write data simultaneously or read and write it at the same time can result in corrupted memory and can cause the process to crash.

The cflock tag enables you to ensure that concurrently executing requests do not access the same section of code simultaneously and thus manipulate shared data structures, files, or CFXs inconsistently. It is important to remember that cflock protects code sections not variables.

Lock types

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

Lock scopes and names

The cflock tag prevents simultaneous access to a sections of code, not variables. If you have two sections of code that access the same variable, they too must be synchronized to prevent them form running simultaneously. You do this by identifying the locks with either 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. It is acceptable to use an anonymous lock only when the resource you are protecting is used nowhere else in your code. 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 and application share a single lock.

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

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

The cflock name attribute provides a second mechanism for identifying 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 lock timeouts

You must include a timeout attribute in your cflock tag. It 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 timeout period, ColdFusion generates an exception error, which you can handle using cftry and cfcatch.

If you set the cflock throwOntTmeout attribute to No, processing continues after the timeout at the line after the </cflock> end tag.

Under normal circumstances it should not take more than a few seconds to obtain a lock. Very large timeouts can block request threads for long periods of time and radically decrease throughput. Always use the smallest timeout value that does not result in significant numbers of timeouts.

To prevent unnecessary timeouts, 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 perform a time-consuming activity outside of a cflock tag and assign the results to a Variables scope variable, then assign the shared scope variable to the Variables scope variable's value 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 illustrates this technique:

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

Using administrative lock management

You can specify several types of automatic locking and lock checking in ColdFusion Administrator. Use these options when you are developing your code and if you must maintain existing, poorly locked code.

Automatic lock checking and locking

The Locking page on the Server tab in the ColdFusion Administrator lets you specify the following for variables in each of the three shared memory scopes: Session, Application, and Server.
Type
Description
No automatic checking or locking
ColdFusion does not check for lock use and does not prevent any invalid access of shared variables.
Full checking
ColdFusion generates an exception error when your application attempts to use any variable in the scope without protecting it with a lock.
Automatic read locking
If your application reads a variable without protecting it, ColdFusion creates a read-only lock for the duration of the read. As a result, ColdFusion blocks any attempt to write to the variable (using code within a lock) until the read completes and the read-only lock is released. If your application writes to any variable in the scope without protecting it with a lock, ColdFusion generates an exception error.

Selecting the No automatic checking or locking option results in the most efficient code, but requires you to follow the full rules of locking. You should only select this option after you finish debugging your program.

Full checking is very useful for debugging your code. You get errors to help indicate missing locks. You can leave this feature on in production code to protect against inadvertently unlocked variable accesses, but it adds processor overhead for checking all accesses to shared variables, and all locking problems cause exceptions.

Automatic read locking also adds overhead because ColdFusion must insert read locks and check variable access for locking. However, it can be useful if you already have a site that does not use locking properly. In this case, you must only lock all writes and do not have to add locks around all reads.

Single-threading sessions

The ColdFusion Administrator also allows you to specify single-threaded sessions. If you select this option, each session is handled by a single thread in the ColdFusion Server. As a result, one request from the client must complete before the next one can begin. In this case, you do not need to lock Session variables, but the performance of frames-based pages might be reduced because it prevents simultaneous processing of requests from multiple frames.

Nesting locks and avoiding deadlocks

Inconsistent nesting of cflock tags and inconsistent naming of locks can cause deadlocks (blocked code). If you are nesting locks, you must consistently nest cflock tags in the same order and use consistent lock scopes (or names).

A deadlock is a state in which no request can execute the locked section of the page. Thus, all requests to the protected section of the page are blocked until there is a timeout. The following table shows one scenario that would cause a deadlock:
User 1
User 2
Locks the Session scope.
Locks the Application scope.
Deadlock: Tries to lock application scope, but application scope is already locked by User 2.
Deadlock: Tries to lock session, but session is already locked by User 1.

Once a deadlock occurs, neither of the users can do anything to break the deadlock, because the execution of their requests is blocked until the deadlock is resolved by a lock timeout.

In addition, if you nest locks of different types, you can cause a deadlock. An example of this is nesting an exclusive lock inside a read lock of the same scope, or of the same name.

In order to avoid a deadlock, you should lock code sections in a well-specified order and name the locks consistently. In particular, if you need to lock access to the Server, Application, and Session scopes, you must do so in the following order.

  1. Lock the Session scope. In the cflock tag, specify the scope as "session."
  2. Lock the Application scope. In the cflock tag, specify the scope as "application."
  3. Lock the Server scope. In the cflock tag, specify the scope as "server."
  4. Unlock the Server scope.
  5. Unlock the Application scope.
  6. Unlock the Session scope.

Note

You can skip any pair of lock/unlock steps in the preceding list if you do not need to lock a particular scope. For example, you can omit steps 3 and 4 if you do not need to lock the Server scope.