Because multiple threads can process simultaneously within a single request, applications must ensure that data from one thread does not improperly affect data in another thread. ColdFusion provides several scopes that you can use to manage thread data, and a request-level lock mechanism that you use to prevent problems caused by threads that access page-level data. ColdFusion also provides metadata variables that contain any thread-specific output and information about the thread, such as its status and processing time.
Each thread has three special scopes:
The thread-local scope is an implicit scope that contains variables that are available only to the thread, and exist only for the life of the thread. Any variable that you define inside the cfthread tag body without specifying a scope name prefix is in the thread local scope and cannot be accessed or modified by other threads.
To create a thread-local variable, assign the variable in the cfthread tag body without specifying a scope prefix, as in the following lines:
<cfset var index=1> <cfset index=1>
These two lines are equivalent, with one exception: If you use the var keyword, the assignment code must immediately follow the cfthread tag, before any other CFML tags.
The Thread scope contains thread-specific variables and metadata about the thread. Only the owning thread can write data to this scope, but the page thread and all other threads in a request can read the variable values in this scope. Thread scope data remains available until the page and all threads that started from the page finish, even if the page finishes before the threads complete processing.
To create a Thread scope variable, in the cfthread tag body, use the keyword Thread or the name of the thread (for example, myThread) as a prefix. the following examples of creating a Thread scope variable are equivalent:
<cfset Thread.myValue = 27> <cfset myThread.myValue = 27>
To access a thread's Thread scope variables outside the thread, prefix the variable with the thread's name, as in the following example:
<cfset nextValue=myThread.myValue + 1>
Thread scope variables are only available to the page that created the thread or to other threads created by that page. No other page can access the data. If one page must access another page's Thread scope data, you must put the data in a database or file and access it from there.
Each thread's Thread scope is a subscope of a special scope, cfthread, that lasts as long as the request, or until the last thread that it starts completes, whichever is longer. Thus, if you have two threads, myThread1 and myThread2, you can access their Thread scopes as cfthread.myThread1 and cfthread.myThread2 until all threads and the request complete. In most cases, there is no need to use the cfthread scope directly. However, you might use the cfthread scope name in either of the following situations:
The Attributes scope and thread attributes
The Attributes scope contains attributes that are passed to the thread, either individually or in the attributeCollection attribute. The Attributes scope is available only within the thread and only for the life of the thread.
ColdFusion makes a complete (deep) copy of all the attribute variables before passing them to the thread; therefore, the values of the variables inside the thread are independent of the values of any corresponding variables in other threads, including the page thread. For example, if you pass a CFC instance as an attribute to a thread, the thread gets a complete new copy of the CFC, including the contents of its This scope at the time that you create the thread. Any changes made to the original CFC outside the thread, for example, by calling a CFC function, have no effect on the copy that is in the thread. Similarly, any changes to the CFC instance in the thread have no effect on the original CFC instance.
Copying the data ensures that the values passed to threads are thread-safe, because the attribute values cannot be changed by any other thread. If you do not want the data to be duplicated, do not pass it to the thread as an attribute or in the attributeCollection attribute. Instead, keep the data in a scope that the thread can access. An example of an object that should not be passed to the thread as an attribute is a singleton CFC that should never be duplicated. The singleton CFC must be kept in some shared scope and accessed by threads. For more information, see the Using other scopes.
Because ColdFusion copies all attributes by value, you can have multiple threads, for example, threads created dynamically in a loop, that use the same attribute names, but where each thread gets a different value, as shown in the following code excerpt, which creates separate threads to copy each of several files in a directory:
<cfloop query="dir"> <cfset threadname = "thread_" & #i#> <cfset i=i+1> <cfthread name="#threadname#" filename="#dir.name#"> <cffile action="COPY" source="#src#\#filename#" destination="#dest#\#filename#\"> </cfthread> </cfloop>
Threads have access to all the ColdFusion scopes. All the threads run by a page share the same Variables and This scope. All the threads run in a request share the same Form, URL, Request, CGI, Cookie, Session, Application, Server and Client scopes. You must be careful to lock access to these scopes if more than one thread could try to modify the data in the scopes; otherwise you can get deadlocks between threads. For more information, see Locking thread data and resource access.
Although a thread can access all the scopes, it might not be able to write to scopes like Session, Cookie, or Request after the request page processing completes.
If you do not specify a scope prefix on a variable inside a cfthread tag body, ColdFusion checks scopes in the following order to find the variable:
Other scopes are checked in the standard scope checking order.
When an application uses multiple threads, you must be careful to ensure that the threads do not simultaneously attempt to use or modify shared resources that are not themselves thread-safe, including the following items:
For more information on locking code, see cflock and Locking code with cflock in the ColdFusion Developer's Guide.
The Thread scope contains the following variables that provide information about the thread, called metadata.
Variable |
Description |
---|---|
Elapsedtime |
The amount of processor time that has been spent handling the thread. |
Error |
A ColdFusion error structure that contains the keys that you can access in a cfcatch tag. This variable has a value only if an unhandled error occurred during thread processing. For information on handling thread errors, see Handling ColdFusion thread errors. |
Name |
The thread name. |
Output |
Output text that is generated by the thread. Threads cannot display output directly. For more information see Handling thread output. |
Priority |
The thread processing priority, as specified when you created the thread. |
Starttime |
The time at which the thread began processing. |
Status |
The current status of the thread. For information on using the Status in an application, see Using the thread status. |
As with other variables in the Thread scope, thread metadata is available to all of a page's threads by specifying the thread name as a variable prefix. For example, the page thread can get the current elapsed time of the myThread1 thread from the myThread1.ElapsedTime variable.
The metadata is available from the time that you create the thread until the time when the page and all threads started on the page complete processing, even if the page finishes before the threads finish. This way, you can get thread output, error information, and processing information during and after the time when the thread is processing.