ColdFusion 9.0 Resources |
Working with threadsMulti-threaded applications use several building blocks, including the following:
Starting threads inside loopsBecause threads run asynchronously, page level variables can change during thread execution. As a result of this behavior, if you start threads inside a cfloop, and code inside the threads uses the value of the loop iterator (like the index variable, query name, list item), pass the loop iterator to the thread as an attribute. The following example shows the use of threads inside a loop. It uses an indexed cfloop tag to start five threads. Each thread gets the current loop index value in a threadIndex attribute. The thread adds an array entry with the threadIndex attribute value of the thread and the current value of the page cfloop index, pageIndex. After joining the threads, the page displays the array contents. When you run the example, particularly if you run it multiple times, you see that at the time the thread saves data to the array, the value of pageIndex has incremented past the threadIndex value, and multiple threads often have the same pageIndex value; but the multiple threads always have the correct threadIndex value. <cfloop index="pageIndex" from="1" to="5"> <cfthread name="thr#pageIndex#" threadIndex="#pageIndex#" action="run"> <cfset Variables.theOutput[threadIndex]="Thread index attribute:" & threadIndex & " Page index value: " & pageIndex> </cfthread> </cfloop> <cfthread action="join" name="thr1,thr2,thr3,thr4,thr5" timeout=2000/> <cfloop index="j" from="1" to="5"> <cfoutput>#theOutput[j]# <br /></cfoutput> </cfloop> Using the thread statusThe Thread scope status metadata variable lets the page, or any other thread started by the page, determine the status of any thread. The page processing code can then take a necessary action, for example, if the thread has terminated abnormally or has hung. The status variable can have the following values:
Applications can check the thread status to manage processing. For example, an application that requires results from a thread specifies a time-out when it joins the thread; in this case, it can check for the COMPLETED status to ensure that the thread has completed processing and the join did not just result from a time-out. Similarly, an application can check the status value of threads that might not start or might not complete normally, and terminate it if necessary. The example in Ending a thread checks thread status and terminates any threads with RUNNING or NOT_STARTED status. Handling thread outputTo prevent conflicts, only the page thread displays output. Therefore, named threads have the following limitations:
Handling ColdFusion thread errorsIf an error occurs in a thread, page-level processing is not affected, and ColdFusion does not generate an error message. If you do not handle the error by using a try/catch block in the thread code, the thread with the error terminates and the page-level code or other threads can get the error information from the thread metadata Error variable and handle the error appropriately. You cannot use page- or application-based error handling techniques to manage errors that occur during thread execution. For that reason, you cannot use the cferror tag or the onError application event handler for thread errors. Instead, use either of the following techniques:
Handling database transactionsDatabase transactions cannot span threads. For example, consider a page with the following structure: <cftransaction> <cfthread name ="t1" ...> <cfquery name="q1" ...> ... </cfquery> </cfthread> <cfquery name="q2" ...> ... </cfquery> <cfthread action="join" name="t1" ... /> </cftransaction> In this case, query q1 is not included in the transaction that contains query q2. To include both queries in the transaction, you must place the complete transaction in a single thread, using a structure such as the following: <cfthread name ="t1" ...> <cftransaction> <cfquery name="q1" ...> ... </cfquery> <cfquery name="q2" ...> ... </cfquery> </cftransaction> </cfthread> <cfthread action="join" name="t1" ... /> |