0

Thread safety example: Var scope your loop index in ColdFusion CFCs!

ColdFusion

On the Dallas/Ft. Worth ColdFusion User Group email list, someone asked the question whether or not it is important to var scope your indexes in loops and items in loops of structures. While most agreed that it was important, one member contacted me off-list to make the case that Java actually manages the threading and it is a non-issue since ColdFusion 5. If you are new to this concept, the issue boils down to the fact that if you do not var scope local variables in a method, they are accessible and modifiable by other methods in the component since they reside in the variables scope. By adding "var" when setting variables in a method, you are protecting them from other processes outside that method. Example:

After attempting to make my case of why it is important (which fell on deaf ears) I thought it might be beneficial to write a short example that demonstrates a thread safety problem.

First, let's create two components, ThreadKiller.cfc and ThreadSaver.cfc.

 

ThreadSaver.cfc:

<cfcomponent output="false">
	<cffunction name="init" access="public" output="false" returntype="ThreadSaver">
		<cfreturn this />
	</cffunction>
	<cffunction name="countUp" access="public" output="false" returntype="void">
		<cfscript>
		var i = ""; 
		for (i=1;i LTE 10;i=i+1) { countDown(); }
		</cfscript>
	</cffunction>
	<cffunction name="countDown" access="public" output="false" returntype="void">
		<cfscript>
		cool = "yeah";
		var i = ""; 
		for (i=10;i GTE 1;i=i-1) { /* nothing */ }
		</cfscript>
	</cffunction>	    
</cfcomponent>

ThreadKiller.cfc:

<cfcomponent output="false">
	<cffunction name="init" access="public" output="false" returntype="ThreadKiller">
		<cfreturn this />
	</cffunction>	
	<cffunction name="countUp" access="public" output="false" returntype="void">
		<cfscript>
		for (i=1;i LTE 10;i=i+1) { countDown(); } 
		</cfscript>
	</cffunction>
	<cffunction name="countDown" access="public" output="false" returntype="void">
		<cfscript>
		for (i=10;i GTE 1;i=i-1) { /* nothing */ }
		</cfscript>
	</cffunction>	    
</cfcomponent>


As you can see, these two components are virtually identical except for the use of the var scoping in the ThreadSaver.cfc methods. The downfall of ThreadKiller.cfc is the fact that in each iteration of the loop of the countUp() method, the called method countDown() will effectively overwrite the value of "i" setting it back to 1, creating an endless loop. In ThreadSaver.cfc, the two variables "i" are actually seperate containers and do not touch each other.

Now, let's create our test page. Create a fiile named vartest.cfm in the same directory as the CFCs.

vartest.cfm:

<cfset Object = iif(StructKeyExists(url,"killit"),De("ThreadKiller"),De("ThreadSaver")) />
<cfset test = CreateObject("component",Object).init() />
<cfset test.countUp() />

done!

First, let's run the "safe" test.  In your broswer, hit:  
/vartest.cfm

When you run this, you will see that it did its work and then outputted "done!" on the screen.

Now we can do our "killer" test.  In your browser, hit:
/vartext.cfm?killit

Please note that this will spin up your processor until the request times out, and should only be done in a development environment in case you end up having to restart your ColdFusion instance. 

When you run this, you can see that loop never completes and your server isn't happy about it at all! Hopefully this will prove the point that it is definitely important to remember to var scope your index.

tags:
ColdFusion
Cameron Childress said:
 
Using the var scope on indexes is also important with recursive functions (outside CFCs). If you are itterating over a complex and deeply nested structure, forgetting the var scope can be a real killer.
 
posted 603 days ago
Add Comment Reply to: this comment OR this thread
 
Tony Petruzzi said:
 
First off, I can't see any of the text in the codeviews.

Now back to the topic. This is why I follow Peter Bell's way of doing it where he declares a structure called Local right off the bat and just places all variables used in the function within this structure. Now I never have to worry about what to var and what not.
 
posted 603 days ago
Add Comment Reply to: this comment OR this thread
 
 
It's not just Peter Bell's way ;)
http://www.daveshuck.com/blog/index.cfm/2006/3/21/...

About the readability of the code in the code views, I am playing with the CSS on my blog. I will come up with something decent before too long, but style is a real beeeotch for some of us.
 
posted 603 days ago
Add Comment Reply to: this comment OR this thread
 
 
Alright Tony... hopefully you can see the code now. The readability issue was bugging me too.
 
posted 602 days ago
Add Comment Reply to: this comment OR this thread
 
Zach Loch said:
 
Your functions actually are thread safe, as long as the object is created fresh each time threading will not be an issue in your example.

A good test of thread safety would be to replace the two functions with two functions named inc (add one to i) and dec (subtract one from i). Then create a .cfm page that creates the threadKiller.cfc, loops 1,000 times and calls inc then dec, then check the value of i - it should always be 1. Run the page from within two different browser windows to create two threads.

The variable should be secure with the above test because there are two objects instaniated seperately with their own values of i - no issues.

The next step would be to store the .cfc in a shared application scope and instead of having the test pages create the object from scratch they would pluck it out of the application scope, loop, and call inc then dec, then check i. That test could get interesting.

I guess the moral of the story is that if you use createObject to create the object each time threading isn't an issue, if you store the object in a shared scope then threading is an issue.

Or just var scope everything as you suggested and be done with it ;)
 
posted 602 days ago
Add Comment Reply to: this comment OR this thread
 
Cliff Meyers said:
 
It's definitely NOT Peter Bell's way of doing it. The majority of people on the CFCDEV list (myself included) were doing that 2 or 3 years ago, long before Peter Bell "graced" the internet with his blog.
 
posted 600 days ago
Add Comment Reply to: this comment OR this thread
 

Search

Dave at work...