Dealing with Deadlocks


One potential hazard of using <cflock> is that nested locks can lead to a deadlock. A deadlock occurs when two or more locks are initiated on separate templates. Say that you have two pages that lock both the APPLICATION and SESSION scope. The first page, named login.cfm, records a user's name in a SESSION variable and then appends the name to an APPLICATION variable. The APPLICATION variable contains an embedded structure of users who are currently logged in. A second page, logout.cfm, clears the SESSION structure and removes the user's name from the embedded structure in the APPLICATION scope.

These pages behave perfectly if the scopes are locked and nested in the same order. If, however, the locks are nested in a different order, the potential for a deadlock exists. The following code causes a deadlock:

login.cfm:

 <cflock scope="session"         type="exclusive"         timeout="15">  <!---  locked the session scope - now set a session variable  --->  <cfset SESSION.userName=FORM.userName>  <cflock scope="application"          type="exclusive"          timeout="15">  <!---  a nested lock since we are dealing with both scopes at once  --->  <!---  note that this structure was defined on another page somewhere  --->  <cfset APPLICATION.loggedInUsers[SESSION.userName]         = SESSION.userName>  </cflock> </cflock> 

logout.cfm:

 <cflock scope="application"         type="exclusive"         timeout="15">  <!---  locked the application scope FIRST, opposite of the login page!!!  --->  <!---   then we nest a second lock since the session scope is used   --->  <cflock scope="session"          type="exclusive"          timeout="15">  <!--- get rid of the user from the application scope--->  <cfset StructDelete(APPLICATION.SESSION.userName)>  <!--- kill the session --->  <cfset structClear(SESSION)>  </cflock> </cflock> 

Although this code may appear to be sound, it is not. If the login.cfm page runs and is then interrupted by another thread that runs the logout page, a fatal deadlock may occur. The login.cfm page could lock the SESSION scope at the same time the logout.cfm page locks the APPLICATION scope. Then the nested locks will demand exclusive access to the nested scopes. login.cfm will wait for logout.cfm to release the application scope, while logout.cfm will wait for SESSION scope to be released. Both would wait forever if there were not a time-out, but because there is a time-out, a fatal error will occur instead. Regardless, the deadlock causes one of the pages to fail.

To avoid deadlocks, you should always lock and unlock in a controlled and ordered sequence. The recommended order is not arbitrary and is based on the underlying architecture of the ColdFusion engine. Locks should be declared in terms of specificity, moving from most specific (SESSION scope) to least specific (SERVER scope).

You need to declare nested locks in this order:

  1. SESSION scope

  2. APPLICATION scope

  3. SERVER scope

You should unlock in the reverse order:

  1. SERVER scope

  2. APPLICATION scope

  3. SESSION scope

To solve the deadlock in the previous code example, you could simply reverse the order of locking in the login.cfm page so that the APPLICATION scope is locked first rather than second. Finally, you could place all the <cfset> tags on login.cfm in the nested lock.



Macromedia ColdFusion MX 7 Certified Developer Study Guide
Macromedia ColdFusion MX 7 Certified Developer Study Guide
ISBN: 0321330110
EAN: 2147483647
Year: 2004
Pages: 389
Authors: Ben Forta

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net