Creating and managing ColdFusion threads



You use the cfthread tag and the Sleep function to create and manage ColdFusion threads. You manage a thread by doing the following actions:

  • Start the thread running.

  • Temporarily suspend the processing of the thread. This action is useful if one thread must wait for another thread to do processing, but both threads must continue processing without joining.

  • End a thread. You typically end a running thread if there is an error, or if it is still processing after a long time.

  • Have the page or a thread wait until one or more other threads have completed processing before proceeding with its processing, called joining the threads. You typically join threads when one thread requires the results from another thread. For example, if a page uses multiple threads to get several news feeds for display, it joins all the feed threads before it displays the results.

Each thread runs the code inside a cfthread tag body and normally exits when the tag body code completes processing.

Starting a thread

You start a thread by using a cfthread tag with an action attribute value of run. CFML code within the cfthread tag body executes on a separate thread while the page request thread continues processing. Only the page thread can create other threads. A thread that you create with a cfthread tag cannot create a child thread, so you cannot have multiple nested threads.

Optionally, when you start the thread, you can specify a priority level of high, normal (the default), or low to specify the relative amount of time that the processor should devote to the thread. Page-level code always runs at normal priority, so you can give your threads more or less processing time than the page.

For more information on using thread attributes, see The Attributes scope and thread attributes.

Suspending a thread

In some cases, one thread must wait until a second thread completes some operations, but should not wait until the second thread completes all processing, so you cannot just join the threads. For example, one thread might do initialization that multiple threads require, and then it might continue with additional processing. The other threads could suspend themselves until initialization is complete.

The Sleep function and cfthread tag with a sleepaction attribute provide two equivalent mechanisms for doing such synchronization. They suspend the thread processing for a specified period of time. A code loop could test a condition variable and sleep for a period before retesting the condition. When the condition is true (or a value is reached, or some other test is valid), the program exits the loop and the thread continues processing.

The following example shows how one thread could use a sleep function to wait for a second thread to perform some actions.

<!--- ThreadA loops to simulate an activity that might take time. ---> 
<cfthread name="threadA" action="run"> 
        <cfset thread.j=1> 
        <cfloop index="i" from="1" to="1000000"> 
         <cfset thread.j=thread.j+1>  
    </cfloop> 
</cfthread> 
 
<!--- ThreadB loops, waiting until threadA finishes looping 40000 times.  
            the loop code sleeps 1/2 second each time. --->  
<cfthread name="threadB" action="run"> 
    <cfscript> 
        thread.sleepTimes=0; 
        thread.initialized=false; 
        while ((threadA.Status != "TERMINATED") && (threadA.j < 400000)) { 
            sleep(500); 
            thread.sleeptimes++; 
        } 
        // Don't continue processing if threadA terminated abnormally. 
        If (threadA.Status != "TERMINATED") { 
            thread.initialized=true; 
            // Do additional processing here. 
        } 
    </cfscript> 
</cfthread> 
 
<!Join the page thread to thread B. Don't join to thread A.---> 
<cfthread action="join" name="threadB" timeout="10000" /> 
 
<!--- Display the thread information. ---> 
<cfoutput> 
    current threadA index value: #threadA.j#<br /> 
    threadA status: #threadA.Status#<br> 
    threadB status: #threadB.Status#<br> 
    threadB sleepTimes: #threadB.sleepTimes#<br> 
    Is threadB initialized: #threadB.initialized#<br> 
</cfoutput>

Ending a thread

If a thread never completes processing (is hung), it continues to occupy system resources, so it is good practice to have your application check for hung threads and end them. Also consider ending threads that take excessive time to process and might significantly reduce the responsiveness of your application or server.

To end a thread, use the cfthread tag with an action attribute value of terminate, as the following code snippet shows.

<!--- Thread1 sleeps to simulate an activity that might hang. ---> 
<cfthread name="thread1" action="run"> 
        <cfset thread.j=1> 
    <cfset sleep(50000) > 
    </cfthread> 
 
<!--- Thread2 loops to simulate an activity that takes less time. ---> 
<cfthread name="thread2" action="run"> 
        <cfset thread.j=1> 
        <cfloop index="i" from="1" to="10"> 
         <cfset thread.j=thread.j+1>  
    </cfloop> 
</cfthread> 
 
<!--- The page thread sleeps for 1/2 second to let thread  
         processing complete. ---> 
<cfset sleep(500) > 
 
<!--- The page thread loops through the threads and terminates 
            any that are still running or never started.  
        Note the use of the cfthread scope and associative array 
        notation to reference the dynamically named threads without 
        using the Evaluate function. ---> 
<cfloop index="k" from="1" to="2"> 
<cfset theThread=cfthread["thread#k#"]> 
    <cfif ((theThread.Status IS "RUNNING") || (theThread.Status IS "NOT_STARTED"))> 
        <cfthread action="terminate" name="thread#k#" /> 
    </cfif> 
</cfloop> 
 
<!--- Wait 1/2 second to make ensure the termination completes ---> 
<cfset sleep(500) > 
 
<!--- Display the thread information. ---> 
<cfoutput> 
    thread1 index value: #thread1.j#<br /> 
    thread1 status: #thread1.Status#<br> 
    thread2 index value: #thread2.j#<br /> 
    thread2 status: #thread2.Status#<br> 
</cfoutput>
Note: You can also have the ColdFusion Sever Monitor automatically check for and terminate hung threads.

Joining threads

You use the cfthreadtag with an action attribute value of join to join two or more threads. You join threads when one thread depends on one or more other threads completing before it can do some processing. For example, a page can start multiple threads to do processing and join them before it processes the thread results. By default, the join action stops the current thread from doing further processing until all the specified threads complete processing.

You can use a timeout attribute to specify the number of milliseconds that the current thread waits for the thread or threads being joined to finish. If any thread does not finish by the specified time, the current thread proceeds without waiting for the remaining thread or threads to complete.

The following code, for example, joins three threads to the current thread (often, the main page thread). The current thread waits up to six seconds for the other threads to complete, and continues processing if one or more threads do not complete by then.

<cfthread action="join" name="t1,t2,t3" timeout="6000"/>

If the timeout attribute value is 0, the default value, the current thread continues waiting until all joining threads finish. In this case, if the current thread is the page thread, the page continues waiting until the threads are joined, even if you specify a page time-out. As a general rule, specify a timeout value to limit hung threads.