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. All requests to the protected section of the page are blocked until there is a time-out. The following table shows one scenario that would cause a deadlock:
User 1 |
User 2 |
---|---|
Locks the Session scope. |
Locks the Application scope. |
Tries to lock the Application scope, but the Application scope is already locked by User 2. |
Tries to lock the Session scope, but the Session scope is already locked by User 1. |
Neither user's request can proceed, because it is waiting for the other to complete. The two are deadlocked.
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 time-out.
You can also cause deadlocks if you nest locks of different types. An example of this is nesting an exclusive lock inside a read-only lock of the same scope or same name.
In order to avoid a deadlock, 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:
Copying shared variables into the Request scope
You can avoid locking some shared-scope variables multiple times during a request by doing the following:
With this technique the "last request wins." For example, if two requests run simultaneously, and both requests change the values of data that was copied from the shared scope, the data from the last request to finish is saved in the shared scope, and the data from the previous request is not saved.
Locking application variables efficiently
The need to lock application variables can reduce server performance, because all requests that use Application scope variables must wait on a single lock. This issue is a problem even for write-once read-many variables, because you still must ensure the variable exists, and possibly set the value before you can read it.
You can minimize this problem by using a technique such as the following to test for the existence of application variables and set them if they do not exist:
The following code shows this technique:
<!--- Initialize local flag to false. ---> <cfset app_is_initialized = False> <!--- Get a readonly lock ---> <cflock scope="application" type="readonly"> <!--- read init flag and store it in local variable ---> <cfset app_is_initialized = IsDefined("APPLICATION.initialized")> </cflock> <!--- Check the local flag ---> <cfif not app_is_initialized > <!--- Not initialized yet, get exclusive lock to write scope ---> <cflock scope="application" type="exclusive"> <!--- Check nonlocal flag since multiple requests could get to the exclusive lock ---> <cfif not IsDefined("APPLICATION.initialized") > <!--- Do initializations ---> <cfset APPLICATION.varible1 = someValue > ... <!--- Set the Application scope initialization flag ---> <cfset APPLICATION.initialized = "yes"> </cfif> </cflock> </cfif>