|
|
|
<html><head> |
|
<title>thread - Tcl Threading</title> |
|
<style type="text/css"><!-- |
|
HTML { |
|
background: #FFFFFF; |
|
color: black; |
|
} |
|
BODY { |
|
background: #FFFFFF; |
|
color: black; |
|
} |
|
DIV.doctools { |
|
margin-left: 10%; |
|
margin-right: 10%; |
|
} |
|
DIV.doctools H1,DIV.doctools H2 { |
|
margin-left: -5%; |
|
} |
|
H1, H2, H3, H4 { |
|
margin-top: 1em; |
|
font-family: sans-serif; |
|
font-size: large; |
|
color: #005A9C; |
|
background: transparent; |
|
text-align: left; |
|
} |
|
H1.doctools_title { |
|
text-align: center; |
|
} |
|
UL,OL { |
|
margin-right: 0em; |
|
margin-top: 3pt; |
|
margin-bottom: 3pt; |
|
} |
|
UL LI { |
|
list-style: disc; |
|
} |
|
OL LI { |
|
list-style: decimal; |
|
} |
|
DT { |
|
padding-top: 1ex; |
|
} |
|
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL { |
|
font: normal 12pt/14pt sans-serif; |
|
list-style: none; |
|
} |
|
LI.doctools_section, LI.doctools_subsection { |
|
list-style: none; |
|
margin-left: 0em; |
|
text-indent: 0em; |
|
padding: 0em; |
|
} |
|
PRE { |
|
display: block; |
|
font-family: monospace; |
|
white-space: pre; |
|
margin: 0%; |
|
padding-top: 0.5ex; |
|
padding-bottom: 0.5ex; |
|
padding-left: 1ex; |
|
padding-right: 1ex; |
|
width: 100%; |
|
} |
|
PRE.doctools_example { |
|
color: black; |
|
background: #f5dcb3; |
|
border: 1px solid black; |
|
} |
|
UL.doctools_requirements LI, UL.doctools_syntax LI { |
|
list-style: none; |
|
margin-left: 0em; |
|
text-indent: 0em; |
|
padding: 0em; |
|
} |
|
DIV.doctools_synopsis { |
|
color: black; |
|
background: #80ffff; |
|
border: 1px solid black; |
|
font-family: serif; |
|
margin-top: 1em; |
|
margin-bottom: 1em; |
|
} |
|
UL.doctools_syntax { |
|
margin-top: 1em; |
|
border-top: 1px solid black; |
|
} |
|
UL.doctools_requirements { |
|
margin-bottom: 1em; |
|
border-bottom: 1px solid black; |
|
} |
|
--></style> |
|
</head> |
|
<! -- Generated from file '' by tcllib/doctools with format 'html' |
|
--> |
|
<! -- thread.n |
|
--> |
|
<body><div class="doctools"> |
|
<h1 class="doctools_title">thread(n) 2.8 "Tcl Threading"</h1> |
|
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2> |
|
<p>thread - Extension for script access to Tcl threading</p> |
|
</div> |
|
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2> |
|
<ul class="doctools_toc"> |
|
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li> |
|
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li> |
|
<li class="doctools_section"><a href="#section1">Description</a></li> |
|
<li class="doctools_section"><a href="#section2">COMMANDS</a></li> |
|
<li class="doctools_section"><a href="#section3">DISCUSSION</a></li> |
|
<li class="doctools_section"><a href="#see-also">See Also</a></li> |
|
<li class="doctools_section"><a href="#keywords">Keywords</a></li> |
|
</ul> |
|
</div> |
|
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2> |
|
<div class="doctools_synopsis"> |
|
<ul class="doctools_requirements"> |
|
<li>package require <b class="pkgname">Tcl 8.4</b></li> |
|
<li>package require <b class="pkgname">Thread <span class="opt">?2.8?</span></b></li> |
|
</ul> |
|
<ul class="doctools_syntax"> |
|
<li><a href="#1"><b class="cmd">thread::create</b> <span class="opt">?-joinable?</span> <span class="opt">?-preserved?</span> <span class="opt">?script?</span></a></li> |
|
<li><a href="#2"><b class="cmd">thread::preserve</b> <span class="opt">?id?</span></a></li> |
|
<li><a href="#3"><b class="cmd">thread::release</b> <span class="opt">?-wait?</span> <span class="opt">?id?</span></a></li> |
|
<li><a href="#4"><b class="cmd">thread::id</b></a></li> |
|
<li><a href="#5"><b class="cmd">thread::errorproc</b> <span class="opt">?procname?</span></a></li> |
|
<li><a href="#6"><b class="cmd">thread::cancel</b> <span class="opt">?-unwind?</span> <i class="arg">id</i> <span class="opt">?result?</span></a></li> |
|
<li><a href="#7"><b class="cmd">thread::unwind</b></a></li> |
|
<li><a href="#8"><b class="cmd">thread::exit</b> <span class="opt">?status?</span></a></li> |
|
<li><a href="#9"><b class="cmd">thread::names</b></a></li> |
|
<li><a href="#10"><b class="cmd">thread::exists</b> <i class="arg">id</i></a></li> |
|
<li><a href="#11"><b class="cmd">thread::send</b> <span class="opt">?-async?</span> <span class="opt">?-head?</span> <i class="arg">id</i> <i class="arg">script</i> <span class="opt">?varname?</span></a></li> |
|
<li><a href="#12"><b class="cmd">thread::broadcast</b> <i class="arg">script</i></a></li> |
|
<li><a href="#13"><b class="cmd">thread::wait</b></a></li> |
|
<li><a href="#14"><b class="cmd">thread::eval</b> <span class="opt">?-lock mutex?</span> <i class="arg">arg</i> <span class="opt">?arg ...?</span></a></li> |
|
<li><a href="#15"><b class="cmd">thread::join</b> <i class="arg">id</i></a></li> |
|
<li><a href="#16"><b class="cmd">thread::configure</b> <i class="arg">id</i> <span class="opt">?option?</span> <span class="opt">?value?</span> <span class="opt">?...?</span></a></li> |
|
<li><a href="#17"><b class="cmd">thread::transfer</b> <i class="arg">id</i> <i class="arg">channel</i></a></li> |
|
<li><a href="#18"><b class="cmd">thread::detach</b> <i class="arg">channel</i></a></li> |
|
<li><a href="#19"><b class="cmd">thread::attach</b> <i class="arg">channel</i></a></li> |
|
<li><a href="#20"><b class="cmd">thread::mutex</b></a></li> |
|
<li><a href="#21"><b class="cmd">thread::mutex</b> <b class="method">create</b> <span class="opt">?-recursive?</span></a></li> |
|
<li><a href="#22"><b class="cmd">thread::mutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#23"><b class="cmd">thread::mutex</b> <b class="method">lock</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#24"><b class="cmd">thread::mutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#25"><b class="cmd">thread::rwmutex</b></a></li> |
|
<li><a href="#26"><b class="cmd">thread::rwmutex</b> <b class="method">create</b></a></li> |
|
<li><a href="#27"><b class="cmd">thread::rwmutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#28"><b class="cmd">thread::rwmutex</b> <b class="method">rlock</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#29"><b class="cmd">thread::rwmutex</b> <b class="method">wlock</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#30"><b class="cmd">thread::rwmutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></li> |
|
<li><a href="#31"><b class="cmd">thread::cond</b></a></li> |
|
<li><a href="#32"><b class="cmd">thread::cond</b> <b class="method">create</b></a></li> |
|
<li><a href="#33"><b class="cmd">thread::cond</b> <b class="method">destroy</b> <i class="arg">cond</i></a></li> |
|
<li><a href="#34"><b class="cmd">thread::cond</b> <b class="method">notify</b> <i class="arg">cond</i></a></li> |
|
<li><a href="#35"><b class="cmd">thread::cond</b> <b class="method">wait</b> <i class="arg">cond</i> <i class="arg">mutex</i> <span class="opt">?ms?</span></a></li> |
|
</ul> |
|
</div> |
|
</div> |
|
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> |
|
<p>The <b class="package">thread</b> 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 primitives, like mutexes and condition variables.</p> |
|
</div> |
|
<div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> |
|
<p>This section describes commands for creating and destroying threads |
|
and sending scripts to threads for evaluation.</p> |
|
<dl class="doctools_definitions"> |
|
<dt><a name="1"><b class="cmd">thread::create</b> <span class="opt">?-joinable?</span> <span class="opt">?-preserved?</span> <span class="opt">?script?</span></a></dt> |
|
<dd><p>This command creates a thread that contains a Tcl interpreter. |
|
The Tcl interpreter either evaluates the optional <b class="option">script</b>, if |
|
specified, or it waits in the event loop for scripts that arrive via |
|
the <b class="cmd">thread::send</b> command. The result, if any, of the |
|
optional <b class="option">script</b> is never returned to the caller. |
|
The result of <b class="cmd">thread::create</b> is the ID of the thread. This is |
|
the opaque 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 <b class="cmd">thread::release</b> command below).</p> |
|
<p>If the optional <b class="option">script</b> argument contains the <b class="cmd">thread::wait</b> |
|
command the thread will enter into the event loop. If such command is not |
|
found in the <b class="option">script</b> the thread will run the <b class="option">script</b> to |
|
the end and exit. In that case, the handle may be safely ignored since it |
|
refers to a thread which does not exists any more at the time when the |
|
command returns.</p> |
|
<p>Using flag <b class="option">-joinable</b> it is possible to create a joinable |
|
thread, i.e. one upon whose exit can be waited upon by using |
|
<b class="cmd">thread::join</b> command. |
|
Note that failure to join a thread created with <b class="option">-joinable</b> flag |
|
results in resource and memory leaks.</p> |
|
<p>Threads created by the <b class="cmd">thread::create</b> cannot be destroyed |
|
forcefully. Consequently, there is no corresponding thread destroy |
|
command. A thread may only be released using the <b class="cmd">thread::release</b> |
|
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 <b class="option">script</b> argument, following the <b class="cmd">thread::wait</b> |
|
command. If this was the last command in the script, as usualy the |
|
case, the thread will exit.</p> |
|
<p>It is possible to create a situation in which it may be impossible |
|
to terminate the thread, for example by putting some endless loop |
|
after the <b class="cmd">thread::wait</b> or entering the event loop again by |
|
doing 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:</p> |
|
<pre class="doctools_example"> |
|
# You should never do ... |
|
set tid [thread::create { |
|
package require Http |
|
thread::wait |
|
vwait forever ; # <-- this! |
|
}] |
|
</pre> |
|
<p>The thread created in the above example will never be able to exit. |
|
After it has been released with the last matching <b class="cmd">thread::release</b> |
|
call, the thread will jump out of the <b class="cmd">thread::wait</b> and continue |
|
to execute commands following. It will enter <b class="cmd">vwait</b> command and |
|
wait endlessly for events. There is no way one can terminate such thread, |
|
so you wouldn't want to do this!</p> |
|
<p>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 |
|
<b class="cmd">thread::preserve</b> and decremented by a call to <b class="cmd">thread::release</b> |
|
command. These two commands implement simple but effective thread |
|
reservation system and offer predictable and controllable thread |
|
termination capabilities. It is however possible to create initialy |
|
preserved threads by using flag <b class="option">-preserved</b> of the |
|
<b class="cmd">thread::create</b> command. Threads created with this flag have the |
|
initial value of the reference counter of 1 (one), and are thus |
|
initially marked reserved.</p></dd> |
|
<dt><a name="2"><b class="cmd">thread::preserve</b> <span class="opt">?id?</span></a></dt> |
|
<dd><p>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 the increment. |
|
If called with the optional thread <b class="option">id</b>, the command preserves |
|
the given thread. Otherwise the current thread is preserved.</p> |
|
<p>With reference counting, one can implement controlled access to a |
|
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 signalizes that |
|
he/she has finished using the thread.</p></dd> |
|
<dt><a name="3"><b class="cmd">thread::release</b> <span class="opt">?-wait?</span> <span class="opt">?id?</span></a></dt> |
|
<dd><p>This command decrements the thread reference counter. Each call to |
|
this command decrements the reference counter by one (1). |
|
If called with the optional thread <b class="option">id</b>, the command releases |
|
the given thread. Otherwise, the current thread is released. |
|
Command returns the value of the reference counter after the decrement. |
|
When the reference counter reaches zero (0), the target thread is |
|
marked for termination. You should not reference the thread after the |
|
<b class="cmd">thread::release</b> command returns zero or negative integer. |
|
The handle of the thread goes out of scope and should not be used any |
|
more. Any following reference to the same thread handle will result |
|
in Tcl error.</p> |
|
<p>Optional flag <b class="option">-wait</b> 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 |
|
<b class="option">-wait</b>, since this may block the caller thread indefinitely. |
|
This option has been implemented for some special uses of the extension |
|
and is deprecated for regular use. Regular users should create joinable |
|
threads by using the <b class="option">-joinable</b> option of the <b class="cmd">thread::create</b> |
|
command and the <b class="cmd">thread::join</b> to wait for thread to exit.</p></dd> |
|
<dt><a name="4"><b class="cmd">thread::id</b></a></dt> |
|
<dd><p>This command returns the ID of the current thread.</p></dd> |
|
<dt><a name="5"><b class="cmd">thread::errorproc</b> <span class="opt">?procname?</span></a></dt> |
|
<dd><p>This command sets a handler for errors that occur in scripts sent |
|
asynchronously, using the <b class="option">-async</b> flag of the |
|
<b class="cmd">thread::send</b> command, to other threads. If no handler |
|
is specified, the current handler is returned. The empty string |
|
resets the handler to default (unspecified) value. |
|
An uncaught error in a thread causes an error message to be sent |
|
to the standard error channel. This default reporting scheme can |
|
be changed by registering a procedure which is called to report |
|
the error. The <i class="arg">procname</i> is called in the interpreter that |
|
invoked the <b class="cmd">thread::errorproc</b> command. The <i class="arg">procname</i> |
|
is called like this:</p> |
|
<pre class="doctools_example"> |
|
myerrorproc thread_id errorInfo |
|
</pre> |
|
</dd> |
|
<dt><a name="6"><b class="cmd">thread::cancel</b> <span class="opt">?-unwind?</span> <i class="arg">id</i> <span class="opt">?result?</span></a></dt> |
|
<dd><p>This command requires Tcl version 8.6 or higher.</p> |
|
<p>Cancels the script being evaluated in the thread given by the <i class="arg">id</i> |
|
parameter. Without the <b class="option">-unwind</b> switch the evaluation stack for |
|
the interpreter is unwound until an enclosing catch command is found or |
|
there are no further invocations of the interpreter left on the call |
|
stack. With the <b class="option">-unwind</b> switch the evaluation stack for the |
|
interpreter is unwound without regard to any intervening catch command |
|
until there are no further invocations of the interpreter left on the |
|
call stack. If <i class="arg">result</i> is present, it will be used as the error |
|
message string; otherwise, a default error message string will be used.</p></dd> |
|
<dt><a name="7"><b class="cmd">thread::unwind</b></a></dt> |
|
<dd><p>Use of this command is deprecated in favour of more advanced thread |
|
reservation system implemented with <b class="cmd">thread::preserve</b> and |
|
<b class="cmd">thread::release</b> commands. Support for <b class="cmd">thread::unwind</b> |
|
command will dissapear in some future major release of the extension.</p> |
|
<p>This command stops a prior <b class="cmd">thread::wait</b> command. Execution of |
|
the script passed to newly created thread will continue from the |
|
<b class="cmd">thread::wait</b> command. If <b class="cmd">thread::wait</b> was the last command |
|
in the script, the thread will exit. The command returns empty result |
|
but may trigger Tcl error with the message "target thread died" in some |
|
situations.</p></dd> |
|
<dt><a name="8"><b class="cmd">thread::exit</b> <span class="opt">?status?</span></a></dt> |
|
<dd><p>Use of this command is deprecated in favour of more advanced thread |
|
reservation system implemented with <b class="cmd">thread::preserve</b> and |
|
<b class="cmd">thread::release</b> commands. Support for <b class="cmd">thread::exit</b> |
|
command will dissapear in some future major release of the extension.</p> |
|
<p>This command forces a thread stuck in the <b class="cmd">thread::wait</b> command to |
|
unconditionaly exit. The thread's exit status defaults to 666 and can be |
|
specified using the optional <i class="arg">status</i> argument. The execution of |
|
<b class="cmd">thread::exit</b> command is guaranteed to leave the program memory in the |
|
unconsistent state, produce memory leaks and otherwise affect other subsytem(s) |
|
of the Tcl application in an unpredictable manner. The command returns empty |
|
result but may trigger Tcl error with the message "target thread died" in some |
|
situations.</p></dd> |
|
<dt><a name="9"><b class="cmd">thread::names</b></a></dt> |
|
<dd><p>This command returns a list of thread IDs. These are only for |
|
threads that have been created via <b class="cmd">thread::create</b> command. |
|
If your application creates other threads at the C level, they |
|
are not reported by this command.</p></dd> |
|
<dt><a name="10"><b class="cmd">thread::exists</b> <i class="arg">id</i></a></dt> |
|
<dd><p>Returns true (1) if thread given by the <i class="arg">id</i> parameter exists, |
|
false (0) otherwise. This applies only for threads that have |
|
been created via <b class="cmd">thread::create</b> command.</p></dd> |
|
<dt><a name="11"><b class="cmd">thread::send</b> <span class="opt">?-async?</span> <span class="opt">?-head?</span> <i class="arg">id</i> <i class="arg">script</i> <span class="opt">?varname?</span></a></dt> |
|
<dd><p>This command passes a <i class="arg">script</i> to another thread and, optionally, |
|
waits for the result. If the <b class="option">-async</b> flag is specified, the |
|
command 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 for threads |
|
created without a startup script. Threads can enter the event loop |
|
explicitly by calling <b class="cmd">thread::wait</b> or any other relevant Tcl/Tk |
|
command, like <b class="cmd">update</b>, <b class="cmd">vwait</b>, etc.</p> |
|
<p>Optional <b class="option">varname</b> specifies name of the variable to store |
|
the result of the <i class="arg">script</i>. Without the <b class="option">-async</b> flag, |
|
the command returns the evaluation code, similarily to the standard |
|
Tcl <b class="cmd">catch</b> command. If, however, the <b class="option">-async</b> flag is |
|
specified, the command returns immediately and caller can later |
|
<b class="cmd">vwait</b> on <span class="opt">?varname?</span> to get the result of the passed <i class="arg">script</i></p> |
|
<pre class="doctools_example"> |
|
set 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 |
|
} |
|
</pre> |
|
<p>In the above example, two threads were fed work and both of them were |
|
instructed to signalize the same variable "result" in the calling 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.</p> |
|
<p>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 event queue of the target thread. |
|
Using the optional <span class="opt">?-head?</span> switch, scripts posted to the thread's |
|
event queue can be placed on the head, instead on the tail of the queue, |
|
thus being executed in the LIFO fashion.</p></dd> |
|
<dt><a name="12"><b class="cmd">thread::broadcast</b> <i class="arg">script</i></a></dt> |
|
<dd><p>This command passes a <i class="arg">script</i> to all threads created by the |
|
package for execution. It does not wait for response from any of |
|
the threads.</p></dd> |
|
<dt><a name="13"><b class="cmd">thread::wait</b></a></dt> |
|
<dd><p>This enters the event loop so a thread can receive messages from |
|
the <b class="cmd">thread::send</b> command. This command should only be used |
|
within the script passed to the <b class="cmd">thread::create</b>. It should |
|
be the very last command in the script. If this is not the case, |
|
the exiting thread will continue executing the script lines past |
|
the <b class="cmd">thread::wait</b> which is usually not what you want and/or |
|
expect.</p> |
|
<pre class="doctools_example"> |
|
set t1 [thread::create { |
|
# |
|
# Do some initialization work here |
|
# |
|
thread::wait ; # Enter the event loop |
|
}] |
|
</pre> |
|
</dd> |
|
<dt><a name="14"><b class="cmd">thread::eval</b> <span class="opt">?-lock mutex?</span> <i class="arg">arg</i> <span class="opt">?arg ...?</span></a></dt> |
|
<dd><p>This command concatenates passed arguments and evaluates the |
|
resulting script under the mutex protection. If no mutex is |
|
specified by using the <span class="opt">?-lock mutex?</span> optional argument, |
|
the internal static mutex is used.</p></dd> |
|
<dt><a name="15"><b class="cmd">thread::join</b> <i class="arg">id</i></a></dt> |
|
<dd><p>This command waits for the thread with ID <i class="arg">id</i> 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.</p></dd> |
|
<dt><a name="16"><b class="cmd">thread::configure</b> <i class="arg">id</i> <span class="opt">?option?</span> <span class="opt">?value?</span> <span class="opt">?...?</span></a></dt> |
|
<dd><p>This command configures various low-level aspects of the thread with |
|
ID <i class="arg">id</i> in the similar way as the standard Tcl command |
|
<b class="cmd">fconfigure</b> configures some Tcl channel options. Options currently |
|
supported are: <b class="option">-eventmark</b> and <b class="option">-unwindonerror</b>.</p> |
|
<p>The <b class="option">-eventmark</b> option, when set, limits the number of |
|
asynchronously posted scripts to the thread event loop. |
|
The <b class="cmd">thread::send -async</b> command will block until the number |
|
of pending scripts in the event loop does not drop below the value |
|
configured with <b class="option">-eventmark</b>. Default value for the |
|
<b class="option">-eventmark</b> is 0 (zero) which effectively disables the checking, |
|
i.e. allows for unlimited number of posted scripts.</p> |
|
<p>The <b class="option">-unwindonerror</b> option, when set, causes the |
|
target thread to unwind if the result of the script processing |
|
resulted in error. Default value for the <b class="option">-unwindonerror</b> |
|
is 0 (false), i.e. thread continues to process scripts after one |
|
of the posted scripts fails.</p></dd> |
|
<dt><a name="17"><b class="cmd">thread::transfer</b> <i class="arg">id</i> <i class="arg">channel</i></a></dt> |
|
<dd><p>This moves the specified <i class="arg">channel</i> from the current thread |
|
and interpreter to the main interpreter of the thread with the |
|
given <i class="arg">id</i>. After the move the current interpreter has no |
|
access to the channel any more, but the main interpreter of the |
|
target thread will be able to use it from now on. |
|
The command waits until the other thread has incorporated the |
|
channel. Because of this it is possible to deadlock the |
|
participating threads by commanding the other through a |
|
synchronous <b class="cmd">thread::send</b> to transfer a channel to 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 |
|
sending thread. This automatically excludes the special channels |
|
for standard input, output and error.</p> |
|
<p>Due to the internal Tcl core implementation and the restriction on |
|
transferring shared channels, one has to take extra measures when |
|
transferring socket channels created by accepting the connection |
|
out of the <b class="cmd">socket</b> commands callback procedures:</p> |
|
<pre class="doctools_example"> |
|
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 |
|
} |
|
</pre> |
|
</dd> |
|
<dt><a name="18"><b class="cmd">thread::detach</b> <i class="arg">channel</i></a></dt> |
|
<dd><p>This detaches the specified <i class="arg">channel</i> 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 state until some other |
|
(or the same) thread attaches the channel again with <b class="cmd">thread::attach</b>. |
|
Restrictions: same as for transferring shared channels with the |
|
<b class="cmd">thread::transfer</b> command.</p></dd> |
|
<dt><a name="19"><b class="cmd">thread::attach</b> <i class="arg">channel</i></a></dt> |
|
<dd><p>This attaches the previously detached <i class="arg">channel</i> in the |
|
current thread/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 <i class="arg">channel</i> cannot be |
|
found in the list of detached channels and/or in the current |
|
interpreter.</p></dd> |
|
<dt><a name="20"><b class="cmd">thread::mutex</b></a></dt> |
|
<dd><p>Mutexes 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 mutexes can 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, otherwise, the mutex will never be |
|
released, which would lead to various deadlock situations.</p> |
|
<p>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.</p> |
|
<p>The <b class="cmd">thread::mutex</b> command supports following subcommands and options:</p> |
|
<dl class="doctools_definitions"> |
|
<dt><a name="21"><b class="cmd">thread::mutex</b> <b class="method">create</b> <span class="opt">?-recursive?</span></a></dt> |
|
<dd><p>Creates the mutex and returns it's opaque handle. This handle |
|
should be used for any future reference to the newly created mutex. |
|
If no optional <span class="opt">?-recursive?</span> argument was specified, the command |
|
creates the exclusive mutex. With the <span class="opt">?-recursive?</span> argument, |
|
the command creates a recursive mutex.</p></dd> |
|
<dt><a name="22"><b class="cmd">thread::mutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Destroys the <i class="arg">mutex</i>. Mutex should be in unlocked state before |
|
the destroy attempt. If the mutex is locked, the command will throw |
|
Tcl error.</p></dd> |
|
<dt><a name="23"><b class="cmd">thread::mutex</b> <b class="method">lock</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Locks the <i class="arg">mutex</i>. Locking the exclusive mutex may throw Tcl |
|
error if on attempt to lock the same mutex twice from the 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.</p></dd> |
|
<dt><a name="24"><b class="cmd">thread::mutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Unlocks the <i class="arg">mutex</i> so some other thread may lock it again. |
|
Attempt to unlock the already unlocked mutex will throw Tcl error.</p></dd> |
|
</dl></dd> |
|
<dt><a name="25"><b class="cmd">thread::rwmutex</b></a></dt> |
|
<dd><p>This 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 resource gets mostly read and seldom modified, |
|
you might gain some performace by using reader/writer mutexes instead of |
|
exclusive or recursive mutexes.</p> |
|
<p>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.</p> |
|
<p>The <b class="cmd">thread::rwmutex</b> command supports following subcommands and options:</p> |
|
<dl class="doctools_definitions"> |
|
<dt><a name="26"><b class="cmd">thread::rwmutex</b> <b class="method">create</b></a></dt> |
|
<dd><p>Creates the reader/writer mutex and returns it's opaque handle. |
|
This handle should be used for any future reference to the newly |
|
created mutex.</p></dd> |
|
<dt><a name="27"><b class="cmd">thread::rwmutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Destroys the reader/writer <i class="arg">mutex</i>. If the mutex is already locked, |
|
attempt to destroy it will throw Tcl error.</p></dd> |
|
<dt><a name="28"><b class="cmd">thread::rwmutex</b> <b class="method">rlock</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Locks the <i class="arg">mutex</i> for reading. More than one thread may read-lock |
|
the same <i class="arg">mutex</i> at the same time.</p></dd> |
|
<dt><a name="29"><b class="cmd">thread::rwmutex</b> <b class="method">wlock</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Locks the <i class="arg">mutex</i> for writing. Only one thread may write-lock |
|
the same <i class="arg">mutex</i> at the same time. Attempt to write-lock same |
|
<i class="arg">mutex</i> twice from the same thread will throw Tcl error.</p></dd> |
|
<dt><a name="30"><b class="cmd">thread::rwmutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></dt> |
|
<dd><p>Unlocks the <i class="arg">mutex</i> so some other thread may lock it again. |
|
Attempt to unlock already unlocked <i class="arg">mutex</i> will throw Tcl error.</p></dd> |
|
</dl></dd> |
|
<dt><a name="31"><b class="cmd">thread::cond</b></a></dt> |
|
<dd><p>This command provides script-level access to condition variables. |
|
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 you attempt |
|
to use other type of mutex in conjuction with the condition |
|
variable, a Tcl error will be thrown.</p> |
|
<p>The command supports following subcommands and options:</p> |
|
<dl class="doctools_definitions"> |
|
<dt><a name="32"><b class="cmd">thread::cond</b> <b class="method">create</b></a></dt> |
|
<dd><p>Creates the condition variable and returns it's opaque handle. |
|
This handle should be used for any future reference to newly |
|
created condition variable.</p></dd> |
|
<dt><a name="33"><b class="cmd">thread::cond</b> <b class="method">destroy</b> <i class="arg">cond</i></a></dt> |
|
<dd><p>Destroys condition variable <i class="arg">cond</i>. Extreme care has to be taken |
|
that nobody is using (i.e. waiting on) the condition variable, |
|
otherwise unexpected errors may happen.</p></dd> |
|
<dt><a name="34"><b class="cmd">thread::cond</b> <b class="method">notify</b> <i class="arg">cond</i></a></dt> |
|
<dd><p>Wakes up all threads waiting on the condition variable <i class="arg">cond</i>.</p></dd> |
|
<dt><a name="35"><b class="cmd">thread::cond</b> <b class="method">wait</b> <i class="arg">cond</i> <i class="arg">mutex</i> <span class="opt">?ms?</span></a></dt> |
|
<dd><p>This command is used to suspend program execution until the condition |
|
variable <i class="arg">cond</i> has been signalled or the optional timer has expired. |
|
The exclusive <i class="arg">mutex</i> must be locked by the calling thread on entrance |
|
to this command. If the mutex is not locked, Tcl error is thrown. |
|
While waiting on the <i class="arg">cond</i>, the command releases <i class="arg">mutex</i>. |
|
Before returning to the calling thread, the command re-acquires the |
|
<i class="arg">mutex</i> again. Unlocking the <i class="arg">mutex</i> and waiting on the |
|
condition variable <i class="arg">cond</i> is done atomically.</p> |
|
<p>The <b class="option">ms</b> command option, if given, must be an integer specifying |
|
time interval in milliseconds the command waits to be signalled. |
|
Otherwise the command waits on condition notify forever.</p> |
|
<p>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 accomplished by repeatedly testing a condition under the |
|
mutex protection and waiting on the condition variable until the condition |
|
evaluates to true:</p> |
|
<pre class="doctools_example"> |
|
set mutex [thread::mutex create] |
|
set cond [thread::cond create] |
|
thread::mutex lock $mutex |
|
while {<some_condition_is_true>} { |
|
thread::cond wait $cond $mutex |
|
} |
|
# Do some work under mutex protection |
|
thread::mutex unlock $mutex |
|
</pre> |
|
<p>Repeated testing of the condition is needed since the condition variable |
|
may get signalled without the condition being actually changed (spurious |
|
thread wake-ups, for example).</p></dd> |
|
</dl></dd> |
|
</dl> |
|
</div> |
|
<div id="section3" class="doctools_section"><h2><a name="section3">DISCUSSION</a></h2> |
|
<p>The 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" abstraction is awkward to provide in Tcl because |
|
Tcl makes assumptions about variable and data ownership. Therefore |
|
this extension supports a simple form 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, |
|
<b class="cmd">vwait</b> on variables, and so forth. For the transfer of bulk |
|
information it is possible to move channels between the threads.</p> |
|
<p>For advanced multithreading scripts, script-level access to two |
|
basic synchronization primitives, mutex and condition variables, |
|
is also supported.</p> |
|
</div> |
|
<div id="see-also" class="doctools_section"><h2><a name="see-also">See Also</a></h2> |
|
<p><a href="http://www.tcl.tk/doc/howto/thread_model.html">http://www.tcl.tk/doc/howto/thread_model.html</a>, tpool, tsv, ttrace</p> |
|
</div> |
|
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> |
|
<p>events, message passing, mutex, synchronization, thread</p> |
|
</div> |
|
</div></body></html> |
|
|
|
|