thread(n) thread(n)
NAME
thread - Extension for script access to Tcl threading
SYNOPSIS
package require TTccll 88..33 package require TThhrreeaadd ??22..66??tthhrreeaadd::::ccrreeaattee ?-joinable? ?-preserved? ?script?
tthhrreeaadd::::pprreesseerrvvee ?id?tthhrreeaadd::::rreelleeaassee ?-wait? ?id?
tthhrreeaadd::::iidd tthhrreeaadd::::eerrrroorrpprroocc ?procname? tthhrreeaadd::::uunnwwiinndd tthhrreeaadd::::eexxiitt tthhrreeaadd::::nnaammeess tthhrreeaadd::::eexxiissttss idtthhrreeaadd::::sseenndd ?-async? id script ?varname?
tthhrreeaadd::::bbrrooaaddccaasstt id script tthhrreeaadd::::wwaaiitttthhrreeaadd::::eevvaall ?-lock mutex? arg ?arg ...?
tthhrreeaadd::::jjooiinn id tthhrreeaadd::::ccoonnffiigguurree id ?option? ?value? ?...? tthhrreeaadd::::ttrraannssffeerr id channel tthhrreeaadd::::ddeettaacchh channel tthhrreeaadd::::aattttaacchh channel tthhrreeaadd::::mmuutteexxtthhrreeaadd::::mmuutteexx ccrreeaattee ?-recursive?
tthhrreeaadd::::mmuutteexx ddeessttrrooyy mutex tthhrreeaadd::::mmuutteexx lloocckk mutex tthhrreeaadd::::mmuutteexx uunnlloocckk mutex tthhrreeaadd::::rrwwmmuutteexx tthhrreeaadd::::rrwwmmuutteexx ccrreeaattee tthhrreeaadd::::rrwwmmuutteexx ddeessttrrooyy mutex tthhrreeaadd::::rrwwmmuutteexx rrlloocckk mutex tthhrreeaadd::::rrwwmmuutteexx wwlloocckk mutex tthhrreeaadd::::rrwwmmuutteexx uunnlloocckk mutex tthhrreeaadd::::ccoonndd tthhrreeaadd::::ccoonndd ccrreeaattee tthhrreeaadd::::ccoonndd ddeessttrrooyy cond tthhrreeaadd::::ccoonndd nnoottiiffyy cond tthhrreeaadd::::ccoonndd wwaaiitt cond mutex ?ms?DESCRIPTION
The tthhrreeaadd extension creates threads that contain Tcl interpreters, and
it lets you send scripts to those threads for evaluation. Additionaly,
it provides script-level access to basic thread synchronization primi-
tives, like mutexes and condition variables. CCOOMMMMAANNDDSSThis section describes commands for creating and destroying threads and
sending scripts to threads for evaluation.
tthhrreeaadd::::ccrreeaattee ?-joinable? ?-preserved? ?script?
This command creates a thread that contains a Tcl interpreter.
The Tcl interpreter either evaluates the optional ssccrriipptt, if specified, or it waits in the event loop for scripts that arrive via the tthhrreeaadd::::sseenndd command. The result, if any, of the optional ssccrriipptt is never returned to the caller. The result oftthhrreeaadd::::ccrreeaattee is the ID of the thread. This is the small inte-
ger handle which identifies the newly created thread for all
other package commands. The handle of the thread goes out of
scope automatically when thread is marked for exit (see the
tthhrreeaadd::::rreelleeaassee command below).If the optional ssccrriipptt argument contains the tthhrreeaadd::::wwaaiitt com-
mand the thread will enter into the event loop. If such command
is not found in the ssccrriipptt the thread will run the ssccrriipptt to
the end and exit. In that case, the handle may be safely ignoredsince it refers to a thread which does not exists any more at
the time when the command returns.Using flag -jjooiinnaabbllee it is possible to create a joinable thread,
i.e. one upon whose exit can be waited upon by usingtthhrreeaadd::::jjooiinn command. Note that only Tcl8.4+ core supports join-
able threads. Note also that failure to join a thread created
with -jjooiinnaabbllee flag results in resource and memory leaks.
Threads created by the tthhrreeaadd::::ccrreeaattee cannot be destroyed force-
fully. Consequently, there is no corresponding thread destroy
command. A thread may only be released using the tthhrreeaadd::::rreelleeaassee
and if its internal reference count drops to zero, the thread is
marked for exit. This kicks the thread out of the event loop
servicing and the thread continues to execute commands passed in
the ssccrriipptt argument, following the tthhrreeaadd::::wwaaiitt command. If this was the last command in the script, as usualy the case, thethread will exit.
It is possible to create a situation in which it may be impossi-
ble to terminate the thread, for example by putting some endless
loop after the tthhrreeaadd::::wwaaiitt or entering the event loop again bydoing an vwait-type of command. In such cases, the thread may
never exit. This is considered to be a bad practice and should be avoided if possible. This is best illustrated by the example below:# You should never do ...
set tid [thread::create {
package require Httpthread::wait
vwait forever ; # <- this!
}]The thread created in the above example will never be able to
exit. After it has been released with the last matchingtthhrreeaadd::::rreelleeaassee call, the thread will jump out of the
tthhrreeaadd::::wwaaiitt and continue to execute commands following. It will enter vvwwaaiitt command and wait endlessly for events. There is noway one can terminate such thread, so you wouldn't want to do
this! Each newly created has its internal reference counter set to 0 (zero), i.e. it is unreserved. This counter gets incremented by a call to tthhrreeaadd::::pprreesseerrvvee and decremented by a call to tthhrreeaadd::::rreelleeaassee command. These two commands implement simple buteffective thread reservation system and offer predictable and
controllable thread termination capabilities. It is however pos-
sible to create initialy preserved threads by using flag -pprree-
sseerrvveedd of the tthhrreeaadd::::ccrreeaattee command. Threads created with this flag have the initial value of the reference counter of 1 (one), and are thus initially marked reserved. tthhrreeaadd::::pprreesseerrvvee ?id?This command increments the thread reference counter. Each call
to this command increments the reference counter by one (1). Command returns the value of the reference counter after theincrement. If called with the optional thread iidd, the command
preserves the given thread. Otherwise the current thread is pre-
served. With reference counting, one can implement controlled access toa shared Tcl thread. By incrementing the reference counter, the
caller signalizes that he/she wishes to use the thread for a
longer period of time. By decrementing the counter, caller sig-
nalizes that he/she has finished using the thread.
tthhrreeaadd::::rreelleeaassee ?-wait? ?id?
This command decrements the thread reference counter. Each call
to this command decrements the reference counter by one (1). Ifcalled with the optional thread iidd, the command releases the
given thread. Otherwise, the current thread is released. Com-
mand returns the value of the reference counter after the decre-
ment. When the reference counter reaches zero (0), the targetthread is marked for termination. You should not reference the
thread after the tthhrreeaadd::::rreelleeaassee command returns zero or nega-
tive integer. The handle of the thread goes out of scope and
should not be used any more. Any following reference to the samethread handle will result in Tcl error.
Optional flag -wwaaiitt instructs the caller thread to wait for the
target thread to exit, if the effect of the command would result
in termination of the target thread, i.e. if the return result
would be zero (0). Without the flag, the caller thread does not
wait for the target thread to exit. Care must be taken when
using the -wwaaiitt, since this may block the caller thread indefi-
nitely. This option has been implemented for users of Tcl 8.3 version only. Users of Tcl 8.4 or later should create joinablethreads, by using the -jjooiinnaabbllee option of the tthhrreeaadd::::ccrreeaattee
command and the tthhrreeaadd::::jjooiinn to wait for thread exit.
tthhrreeaadd::::iiddThis command returns the ID of the current thread.
tthhrreeaadd::::eerrrroorrpprroocc ?procname? This command sets a handler for errors that occur in scriptssent asynchronously, using the -aassyynncc flag of the tthhrreeaadd::::sseenndd
command, to other threads. If no handler is specified, the cur-
rent handler is returned. The empty string resets the handler todefault (unspecified) value. An uncaught error in a thread
causes an error message to be sent to the standard error chan-
nel. This default reporting scheme can be changed by registering a procedure which is called to report the error. The procname is called in the interpreter that invoked the tthhrreeaadd::::eerrrroorrpprroocc command. The procname is called like this:myerrorproc threadid errorInfo
tthhrreeaadd::::uunnwwiinndd Use of this command is deprecated in favour of more advancedthread reservation system implemented with tthhrreeaadd::::pprreesseerrvvee and
tthhrreeaadd::::rreelleeaassee commands. Support for tthhrreeaadd::::uunnwwiinndd command will dissapear in some future major release of the extension. This command stops a prior tthhrreeaadd::::wwaaiitt command. Execution ofthe script passed to newly created thread will continue from the
tthhrreeaadd::::wwaaiitt command. If tthhrreeaadd::::wwaaiitt was the last command inthe script, the thread will exit. The command returns empty
result but may trigger Tcl error with the message "target thread
died" in some situations. tthhrreeaadd::::eexxiitt Use of this command is deprecated in favour of more advancedthread reservation system implemented with tthhrreeaadd::::pprreesseerrvvee and
tthhrreeaadd::::rreelleeaassee commands. Support for tthhrreeaadd::::eexxiitt command will dissapear in some future major release of the extension.This command forces a thread stuck in the tthhrreeaadd::::wwaaiitt command
to unconditionaly exit. The execution of tthhrreeaadd::::eexxiitt command is guaranteed to leave the program memory in the unconsistentstate, produce memory leaks and otherwise affect other sub-
sytem(s) of the Tcl application in an unpredictable manner. The command returns empty result but may trigger Tcl error with themessage "target thread died" in some situations.
tthhrreeaadd::::nnaammeessThis command returns a list of thread IDs. These are only for
threads that have been created via tthhrreeaadd::::ccrreeaattee command. If
your application creates other threads at the C level, they are
not reported by this command. tthhrreeaadd::::eexxiissttss idReturns true (1) if thread given by the id parameter exists,
false (0) otherwise. This applies only for threads that have
been created via tthhrreeaadd::::ccrreeaattee command.tthhrreeaadd::::sseenndd ?-async? id script ?varname?
This command passes a script to another thread and, optionally,
waits for the result. If the -aassyynncc flag is specified, the com-
mand does not wait for the result and it returns empty string.The target thread must enter it's event loop in order to receive
scripts sent via this command. This is done by default forthreads created without a startup script. Threads can enter the
event loop explicitly by calling tthhrreeaadd::::wwaaiitt or any other rele-
vant Tcl/Tk command, like uuppddaattee, vvwwaaiitt, etc. Optional vvaarrnnaammee specifies name of the variable to store theresult of the script. Without the -aassyynncc flag, the command
returns the evaluation code, similarily to the standard Tclccaattcchh command. If, however, the -aassyynncc flag is specified, the
command returns immediately and caller can later vvwwaaiitt on ?var-
name? to get the result of the passed scriptset t1 [thread::create]
set t2 [thread::create]
thread::send -async $t1 "set a 1" result
thread::send -async $t2 "set b 2" result
for {set i 0} {$i < 2} {incr i} {
vwait result }In the above example, two threads were fed work and both of them
were instructed to signalize the same variable "result" in thecalling thread. The caller entered the event loop twice to get
both results. Note, however, that the order of the received results may vary, depending on the current system load, type of work done, etc, etc.Many threads can simultaneously send scripts to the target
thread for execution. All of them are entered into the event
queue of the target thread and executed on the FIFO basis,
intermingled with optional other events pending in the eventqueue of the target thread.
tthhrreeaadd::::bbrrooaaddccaasstt id scriptThis command passes a script to all threads created by the pack-
age for execution. It does not wait for response from any of thethreads.
tthhrreeaadd::::wwaaiittThis enters the event loop so a thread can receive messages from
the tthhrreeaadd::::sseenndd command. This command should only be used within the script passed to the tthhrreeaadd::::ccrreeaattee. It should be the very last command in the script. If this is not the case, theexiting thread will continue executing the script lines pass the
tthhrreeaadd::::wwaaiitt which is usually not what you want and/or expect.set t1 [thread::create {
#
# Do some initialization work here
#
thread::wait ; # Enter the event loop
}]tthhrreeaadd::::eevvaall ?-lock mutex? arg ?arg ...?
This command concatenates passed arguments and evaluates the resulting script under the mutex protection. If no mutex isspecified by using the ?-lock mutex? optional argument, the
internal static mutex is used. tthhrreeaadd::::jjooiinn idThis command waits for the thread with ID id to exit and then
returns it's exit code. Errors will be returned for threads
which are not joinable or already waited upon by another thread.
Upon the join the handle of the thread has gone out of scope and
should not be used any more.NOTE: This command is available only when loaded into the
Tcl8.4+ shell. tthhrreeaadd::::ccoonnffiigguurree id ?option? ?value? ?...?This command configures various low-level aspects of the thread
with ID id in the similar way as the standard Tcl command ffccoonn-
ffiigguurree configures some Tcl channel options. Options currentlysupported are: -eevveennttmmaarrkk and -uunnwwiinnddoonneerrrroorr.
The -eevveennttmmaarrkk option, when set, limits the number of asyn-
chronously posted scripts to the thread event loop. The
tthhrreeaadd::::sseenndd -aassyynncc command will block until the number of pend-
ing scripts in the event loop does not drop below the value con-
figured with -eevveennttmmaarrkk. Default value for the -eevveennttmmaarrkk is 0
(zero) which effectively disables the checking, i.e. allows for unlimited number of posted scripts.The -uunnwwiinnddoonneerrrroorr option, when set, causes the target thread to
unwind if the result of the script processing resulted in error.Default value for the -uunnwwiinnddoonneerrrroorr is 0 (false), i.e. thread
continues to process scripts after one of the posted scripts fails. tthhrreeaadd::::ttrraannssffeerr id channelThis moves the specified channel from the current thread and
interpreter to the main interpreter of the thread with the given
id. After the move the current interpreter has no access to thechannel any more, but the main interpreter of the target thread
will be able to use it from now on. The command waits until theother thread has incorporated the channel. Because of this it is
possible to deadlock the participating threads by commanding the
other through a synchronous tthhrreeaadd::::sseenndd to transfer a channelto us. This easily extends into longer loops of threads waiting
for each other. Other restrictions: the channel in question must not be shared among multiple interpreters running in the sendingthread. This automatically excludes the special channels for
standard input, output and error. Due to the internal Tcl core implementation and the restriction on transferring shared channels, one has to take extra measureswhen transferring socket channels created by accepting the con-
nection out of the ssoocckkeett commands callback procedures:socket -server Accept 2200
proc Accept {s ipaddr port} {after idle [list Accept $s $ipaddr $port]
} proc Accept {s ipaddr port} {set tid [thread::create]
thread::transfer $tid $s
}NOTE: this command is available only when loaded into the
Tcl8.4+ shell. tthhrreeaadd::::ddeettaacchh channelThis detaches the specified channel from the current thread and
interpreter. After that, the current interpreter has no access to the channel any more. The channel is in the parked stateuntil some other (or the same) thread attaches the channel again
with tthhrreeaadd::::aattttaacchh. Restrictions: same as for transferring shared channels with the tthhrreeaadd::::ttrraannssffeerr command.NOTE: this command is available only when loaded into the
Tcl8.4+ shell. tthhrreeaadd::::aattttaacchh channel This attaches the previously detached channel in the currentthread/interpreter. For already existing channels, the command
does nothing, i.e. it is not an error to attach the same channel more than once. The first operation will actualy perform the operation, while all subsequent operation will just do nothing. Command throws error if the channel cannot be found in the list of detached channels and/or in the current interpreter.NOTE: this command is available only when loaded into the
Tcl8.4+ shell. tthhrreeaadd::::mmuutteexxMutexes are most common thread synchronization primitives. They
are used to synchronize access from two or more threads to one
or more shared resources. This command provides script-level
access to exclusive and/or recursive mutexes. Exclusive mutexescan be locked only once by one thread, while recursive mutexes
can be locked many times by the same thread. For recursive
mutexes, number of lock and unlock operations must match, other-
wise, the mutex will never be released, which would lead to var-
ious deadlock situations.Care has to be taken when using mutexes in an multithreading
program. Improper use of mutexes may lead to various deadlock situations, especially when using exclusive mutexes. The tthhrreeaadd::::mmuutteexx command supports following subcommands and options:tthhrreeaadd::::mmuutteexx ccrreeaattee ?-recursive?
Creates the mutex and returns it's opaque handle. This handle should be used for any future reference to thenewly created mutex. If no optional ?-recursive? argu-
ment was specified, the command creates the exclusivemutex. With the ?-recursive? argument, the command cre-
ates a recursive mutex. tthhrreeaadd::::mmuutteexx ddeessttrrooyy mutex Destroys the mutex. Mutex should be in unlocked state before the destroy attempt. If the mutex is locked, the command will throw Tcl error. tthhrreeaadd::::mmuutteexx lloocckk mutex Locks the mutex. Locking the exclusive mutex may throw Tcl error if on attempt to lock the same mutex twice fromthe same thread. If your program logic forces you to lock
the same mutex twice or more from the same thread (this
may happen in recursive procedure invocations) you should consider using the recursive mutexes. tthhrreeaadd::::mmuutteexx uunnlloocckk mutexUnlocks the mutex so some other thread may lock it again.
Attempt to unlock the already unlocked mutex will throw Tcl error. tthhrreeaadd::::rrwwmmuutteexxThis command creates many-readers/single-writer mutexes.
Reader/writer mutexes allow you to serialize access to a shared resource more optimally. In situations where a shared resourcegets mostly read and seldom modified, you might gain some per-
formace by using reader/writer mutexes instead of exclusive or recursive mutexes.For reading the resource, thread should obtain a read lock on
the resource. Read lock is non-exclusive, meaning that more
than one thread can obtain a read lock to the same resource,
without waiting on other readers. For changing the resource,however, a thread must obtain a exclusive write lock. This lock
effectively blocks all threads from gaining the read-lock while
the resource is been modified by the writer thread. Only after
the write lock has been released, the resource may be read-
locked again. The tthhrreeaadd::::rrwwmmuutteexx command supports following subcommands and options: tthhrreeaadd::::rrwwmmuutteexx ccrreeaattee Creates the reader/writer mutex and returns it's opaquehandle. This handle should be used for any future refer-
ence to the newly created mutex. tthhrreeaadd::::rrwwmmuutteexx ddeessttrrooyy mutex Destroys the reader/writer mutex. If the mutex is already locked, attempt to destroy it will throw Tcl error. tthhrreeaadd::::rrwwmmuutteexx rrlloocckk mutexLocks the mutex for reading. More than one thread may
read-lock the same mutex at the same time.
tthhrreeaadd::::rrwwmmuutteexx wwlloocckk mutexLocks the mutex for writing. Only one thread may write-
lock the same mutex at the same time. Attempt to write-
lock same mutex twice from the same thread will throw Tcl
error. tthhrreeaadd::::rrwwmmuutteexx uunnlloocckk mutexUnlocks the mutex so some other thread may lock it again.
Attempt to unlock already unlocked mutex will throw Tcl error. tthhrreeaadd::::ccoonnddThis command provides script-level access to condition vari-
ables. A condition variable creates a safe environment for the program to test some condition, sleep on it when false and be awakened when it might have become true. A condition variable is always used in the conjuction with an exclusive mutex. If youattempt to use other type of mutex in conjuction with the condi-
tion variable, a Tcl error will be thrown. The command supports following subcommands and options: tthhrreeaadd::::ccoonndd ccrreeaattee Creates the condition variable and returns it's opaquehandle. This handle should be used for any future refer-
ence to newly created condition variable. tthhrreeaadd::::ccoonndd ddeessttrrooyy cond Destroys condition variable cond. Extreme care has to betaken that nobody is using (i.e. waiting on) the condi-
tion variable, otherwise unexpected errors may happen. tthhrreeaadd::::ccoonndd nnoottiiffyy condWakes up all threads waiting on the condition variable
cond. tthhrreeaadd::::ccoonndd wwaaiitt cond mutex ?ms? This command is used to suspend program execution until the condition variable cond has been signalled or the optional timer has expired. The exclusive mutex must belocked by the calling thread on entrance to this command.
If the mutex is not locked, Tcl error is thrown. While waiting on the cond, the command releases mutex. Beforereturning to the calling thread, the command re-acquires
the mutex again. Unlocking the mutex and waiting on the condition variable cond is done atomically.The mmss command option, if given, must be an integer spec-
ifying time interval in milliseconds the command waits to be signalled. Otherwise the command waits on condition notify forever.In multithreading programs, there are many situations
where a thread has to wait for some event to happen until
it is allowed to proceed. This is usually accomplishedby repeatedly testing a condition under the mutex protec-
tion and waiting on the condition variable until the con-
dition evaluates to true:set mutex [thread::mutex create]
set cond [thread::cond create]
thread::mutex lock
while {} { thread::cond wait $cond $mutex
}# Do some work under mutex protection
thread::mutex unlock
Repeated testing of the condition is needed since thecondition variable may get signalled without the condi-
tion being actually changed (spurious thread wake-ups,
for example). DDIISSCCUUSSSSIIOONNThe fundamental threading model in Tcl is that there can be one or more
Tcl interpreters per thread, but each Tcl interpreter should only be
used by a single thread which created it. A "shared memory" abstrac-
tion is awkward to provide in Tcl because Tcl makes assumptions about variable and data ownership. Therefore this extension supports a simpleform of threading where the main thread can manage several background,
or "worker" threads. For example, an event-driven server can pass
requests to worker threads, and then await responses from worker
threads or new client requests. Everything goes through the common Tcl
event loop, so message passing between threads works naturally with
event-driven I/O, vvwwaaiitt on variables, and so forth. For the transfer of
bulk information it is possible to move channels between the threads.
For advanced multithreading scripts, script-level access to two basic
synchronization primitives, mutex and condition variables, is also sup-
ported.SEE ALSO
http://www.tcl.tk/doc/howto/threadmodel.html, tpool, tsv, ttrace
KKEEYYWWOORRDDSSevents, message passing, mutex, synchronization, thread
Tcl Threading 2.6 thread(n)