|
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.
Thread scopesEach thread
has three special scopes:
The thread-local scope
The Thread scope
The Attributes scope
The thread-local scopeThe 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 scopeThe 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 place the data in a database or file and access
it from there.
The Thread scope of each thread 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 can use
the cfthread scope name in either of the following situations:
If you generate the thread name dynamically, you can
avoid using the Evaluate function by using the cfthread scope
with associative array notation, as the following code snippet shows:
<cfset threadname="thread_#N#">
...
<!--- The following two lines are equivalent --->
<cfset threadscopeForNthThread = cfthread[threadname] >
<cfset threadscopeForNthThread = Evaluate(threadname) >
If you have a thread with the same name as a Variables scope
variable, you can access that thread’s Thread scope only by prefacing
the Thread name with cfthread. Otherwise, you access
the Variables scope variable, or get an error.
The Attributes scope and thread attributesThe 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 duplicate data, 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>
Using other scopesThreads 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. 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.
Scope precedenceIf 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:
Function-local, in function definitions in the thread
only
Thread-local
Attributes
Variables
Thread/cfthread
Other scopes are checked in the standard scope checking order.
Locking thread data and resource accessWhen an
application uses multiple threads, 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:
If multiple threads modify a Variables or Request scope
variable, use a Request scope lock to control access to the code
that uses the variable to prevent deadlocks and race conditions.
Similarly, use a Request scope lock around code that accesses built-in
data structures or subscopes of the Variables scope, such as the
Forms variable, that you change in multiple threads.
Multiple threads should not try to access any other shared
resource simultaneously. For example, do not use the same FTP connection
from multiple threads. To prevent this behavior, place the code
that uses the resource in named cflock tags. Use
the same name attribute for all cflock tags around
code that uses a specific resource.
For more information on locking code, see cflock and Locking code with cflock.
Metadata variablesThe 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 the thread generates. 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.
|
|
|