Friday, September 15, 2006

Update to CFThread POC tags

Damon posted an update to the CFThread proof of concept tag that was published some time back. I wanted to do it for a long time but was busy in other Scorpio features and had to keep delaying this. Neverthless better late than never :) This update includes "thread safety" while retaining the old syntax in the original post. Thanks to Dan Switzer, Derek, Mike and all others who provided the valuable feedback on it !

Whats there in the update
  • Thread very much acts like a function and some time little more than that.
  • Any attribute can be passed to cfthread. These attributes can be accessed using 'attributes.<varname>'. These attributes are passed by value and hence they are completely thread safe.
  • Any variable unless defined with a scope prefix goes in thread local scope. So this is slightly different from function. Like function, variable defined in var scope will also go in thread local scope. So in following snippet, x, y, z and a all will be in thread local scope. However since b is directly used inside thread without defining it, it will use it from the page scope.

<cfset x = 10>
<cfset b = 20>
<cfthread name="t1">
<cfset var y = 10>
<cfset x = 20>
<cfset z = y*x>
<cfset a = z*Variables.x>
<cfset a = a/b>

  • All other scope variables will be accessible using the appropriate prefix like "Variables", "request", "Server" etc.
  • Threads have an another scope called thread scope in which only the owner thread can write but all other can read. This scope can be accessed using 'thread' prefix by owner thread or using the thread name by other thread or main page thread. This scope will be useful when the owner thread wants to put some data in it which needs to accessed by other thread. The same thing could have been achieved by all the threads writing to the page scope in its own variable but that needs some discipline from developers and is error prone. Having a separate thread scope which other can read makes it threadsafe and easier for developers.
  • If thread name is dynamic, it will be everyone's question how to access that thread data from another thread or main page. It can be easily done using Variables[threadname].xxx. See the example below.
  • Threads can continue even after the main page is done.

Below is a sample cf code that uses cfthread. (modified version of Dan's example. Thanks Dan !!).

<cfset CRLF = CHR(13) & CHR(10)>
<cfset sDirectory = expandPath(".") & "\tmp" />

<cfloop index="loopcounter" from="1" to="50">
<cfset threadname = "thread_" & #loopcounter#>
<cfthread name="#threadname#" filename="file#loopcounter#.txt" counter="#loopcounter#">
<cfset sOutput = "Content written by thread " & #attributes.counter#>
<cfloop index="i" from="1" to="100">
<cfset sOutput = sOutput & sContent>
<cfset sOutput>
<cfset dest="#sDirectory#\tmp_#attributes.filename#">
<cffile action="write" file="#dest#" output="#sOutput#" />
<cfset thread.msg="Message from thread "&#attributes.counter#>

<cfloop index="loopcounter" from="1" to="50">
<cfset threadname = "thread_" & #loopcounter#>
<cfjoin thread="#threadname#"/>
<cfoutput><br>#threadname# output : #Variables[threadname].msg#</cfoutput>

<br> Work Complete!<br>

Feel free to play around with this tag and send feedbacks if you have any. Once again, as Damon said, this is not a CF feature and hence it is unsupported. On whether it will make it to the Scorpio or not, I can not guarantee anything but stay tuned ;)
Enjoy !


Dan G. Switzer, II said...

Great work!

Andy Allan said...

I haven't tried this as yet, but a big thanks for actually putting it out there!!!