243 lines
9.6 KiB
Groff
243 lines
9.6 KiB
Groff
'\"
|
|
'\" Copyright (c) 1999 Scriptics Corporation
|
|
'\" Copyright (c) 1998 Sun Microsystems, Inc.
|
|
'\"
|
|
'\" See the file "license.terms" for information on usage and redistribution
|
|
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
'\"
|
|
.TH Threads 3 "8.1" Tcl "Tcl Library Procedures"
|
|
.so man.macros
|
|
.BS
|
|
.SH NAME
|
|
Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread \- Tcl thread support
|
|
.SH SYNOPSIS
|
|
.nf
|
|
\fB#include <tcl.h>\fR
|
|
.sp
|
|
void
|
|
\fBTcl_ConditionNotify\fR(\fIcondPtr\fR)
|
|
.sp
|
|
void
|
|
\fBTcl_ConditionWait\fR(\fIcondPtr, mutexPtr, timePtr\fR)
|
|
.sp
|
|
void
|
|
\fBTcl_ConditionFinalize\fR(\fIcondPtr\fR)
|
|
.sp
|
|
Void *
|
|
\fBTcl_GetThreadData\fR(\fIkeyPtr, size\fR)
|
|
.sp
|
|
void
|
|
\fBTcl_MutexLock\fR(\fImutexPtr\fR)
|
|
.sp
|
|
void
|
|
\fBTcl_MutexUnlock\fR(\fImutexPtr\fR)
|
|
.sp
|
|
void
|
|
\fBTcl_MutexFinalize\fR(\fImutexPtr\fR)
|
|
.sp
|
|
int
|
|
\fBTcl_CreateThread\fR(\fIidPtr, proc, clientData, stackSize, flags\fR)
|
|
.sp
|
|
int
|
|
\fBTcl_JoinThread\fR(\fIid, result\fR)
|
|
.SH ARGUMENTS
|
|
.AS Tcl_CreateThreadProc proc out
|
|
.AP Tcl_Condition *condPtr in
|
|
A condition variable, which must be associated with a mutex lock.
|
|
.AP Tcl_Mutex *mutexPtr in
|
|
A mutex lock.
|
|
.AP "const Tcl_Time" *timePtr in
|
|
A time limit on the condition wait. NULL to wait forever.
|
|
Note that a polling value of 0 seconds does not make much sense.
|
|
.AP Tcl_ThreadDataKey *keyPtr in
|
|
This identifies a block of thread local storage. The key should be
|
|
static and process-wide, yet each thread will end up associating
|
|
a different block of storage with this key.
|
|
.AP int *size in
|
|
The size of the thread local storage block. This amount of data
|
|
is allocated and initialized to zero the first time each thread
|
|
calls \fBTcl_GetThreadData\fR.
|
|
.AP Tcl_ThreadId *idPtr out
|
|
The referred storage will contain the id of the newly created thread as
|
|
returned by the operating system.
|
|
.AP Tcl_ThreadId id in
|
|
Id of the thread waited upon.
|
|
.AP Tcl_ThreadCreateProc *proc in
|
|
This procedure will act as the \fBmain()\fR of the newly created
|
|
thread. The specified \fIclientData\fR will be its sole argument.
|
|
.AP ClientData clientData in
|
|
Arbitrary information. Passed as sole argument to the \fIproc\fR.
|
|
.AP int stackSize in
|
|
The size of the stack given to the new thread.
|
|
.AP int flags in
|
|
Bitmask containing flags allowing the caller to modify behavior of
|
|
the new thread.
|
|
.AP int *result out
|
|
The referred storage is used to place the exit code of the thread
|
|
waited upon into it.
|
|
.BE
|
|
.SH INTRODUCTION
|
|
Beginning with the 8.1 release, the Tcl core is thread safe, which
|
|
allows you to incorporate Tcl into multithreaded applications without
|
|
customizing the Tcl core. Starting with the 8.6 release, Tcl
|
|
multithreading support is on by default. To disable Tcl multithreading
|
|
support, you must include the \fB\-\|\-disable-threads\fR option to
|
|
\fBconfigure\fR when you configure and compile your Tcl core.
|
|
.PP
|
|
An important constraint of the Tcl threads implementation is that
|
|
\fIonly the thread that created a Tcl interpreter can use that
|
|
interpreter\fR. In other words, multiple threads can not access
|
|
the same Tcl interpreter. (However, a single thread can safely create
|
|
and use multiple interpreters.)
|
|
.SH DESCRIPTION
|
|
Tcl provides \fBTcl_CreateThread\fR for creating threads. The
|
|
caller can determine the size of the stack given to the new thread and
|
|
modify the behavior through the supplied \fIflags\fR. The value
|
|
\fBTCL_THREAD_STACK_DEFAULT\fR for the \fIstackSize\fR indicates that
|
|
the default size as specified by the operating system is to be used
|
|
for the new thread. As for the flags, currently only the values
|
|
\fBTCL_THREAD_NOFLAGS\fR and \fBTCL_THREAD_JOINABLE\fR are defined. The
|
|
first of them invokes the default behavior with no special settings.
|
|
Using the second value marks the new thread as \fIjoinable\fR. This
|
|
means that another thread can wait for the such marked thread to exit
|
|
and join it.
|
|
.PP
|
|
Restrictions: On some UNIX systems the pthread-library does not
|
|
contain the functionality to specify the stack size of a thread. The
|
|
specified value for the stack size is ignored on these systems.
|
|
Windows currently does not support joinable threads. This
|
|
flag value is therefore ignored on this platform.
|
|
.PP
|
|
Tcl provides the \fBTcl_ExitThread\fR and \fBTcl_FinalizeThread\fR functions
|
|
for terminating threads and invoking optional per-thread exit
|
|
handlers. See the \fBTcl_Exit\fR page for more information on these
|
|
procedures.
|
|
.PP
|
|
The \fBTcl_JoinThread\fR function is provided to allow threads to wait
|
|
upon the exit of another thread, which must have been marked as
|
|
joinable through usage of the \fBTCL_THREAD_JOINABLE\fR-flag during
|
|
its creation via \fBTcl_CreateThread\fR.
|
|
.PP
|
|
Trying to wait for the exit of a non-joinable thread or a thread which
|
|
is already waited upon will result in an error. Waiting for a joinable
|
|
thread which already exited is possible, the system will retain the
|
|
necessary information until after the call to \fBTcl_JoinThread\fR.
|
|
This means that not calling \fBTcl_JoinThread\fR for a joinable thread
|
|
will cause a memory leak.
|
|
.PP
|
|
The \fBTcl_GetThreadData\fR call returns a pointer to a block of
|
|
thread-private data. Its argument is a key that is shared by all threads
|
|
and a size for the block of storage. The storage is automatically
|
|
allocated and initialized to all zeros the first time each thread asks for it.
|
|
The storage is automatically deallocated by \fBTcl_FinalizeThread\fR.
|
|
.SS "SYNCHRONIZATION AND COMMUNICATION"
|
|
Tcl provides \fBTcl_ThreadQueueEvent\fR and \fBTcl_ThreadAlert\fR
|
|
for handling event queuing in multithreaded applications. See
|
|
the \fBNotifier\fR manual page for more information on these procedures.
|
|
.PP
|
|
A mutex is a lock that is used to serialize all threads through a piece
|
|
of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR.
|
|
If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will
|
|
block until \fBTcl_MutexUnlock\fR is called.
|
|
A mutex can be destroyed after its use by calling \fBTcl_MutexFinalize\fR.
|
|
The result of locking a mutex twice from the same thread is undefined.
|
|
On some platforms it will result in a deadlock.
|
|
The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR
|
|
procedures are defined as empty macros if not compiling with threads enabled.
|
|
For declaration of mutexes the \fBTCL_DECLARE_MUTEX\fR macro should be used.
|
|
This macro assures correct mutex handling even when the core is compiled
|
|
without threads enabled.
|
|
.PP
|
|
A condition variable is used as a signaling mechanism:
|
|
a thread can lock a mutex and then wait on a condition variable
|
|
with \fBTcl_ConditionWait\fR. This atomically releases the mutex lock
|
|
and blocks the waiting thread until another thread calls
|
|
\fBTcl_ConditionNotify\fR. The caller of \fBTcl_ConditionNotify\fR should
|
|
have the associated mutex held by previously calling \fBTcl_MutexLock\fR,
|
|
but this is not enforced. Notifying the
|
|
condition variable unblocks all threads waiting on the condition variable,
|
|
but they do not proceed until the mutex is released with \fBTcl_MutexUnlock\fR.
|
|
The implementation of \fBTcl_ConditionWait\fR automatically locks
|
|
the mutex before returning.
|
|
.PP
|
|
The caller of \fBTcl_ConditionWait\fR should be prepared for spurious
|
|
notifications by calling \fBTcl_ConditionWait\fR within a while loop
|
|
that tests some invariant.
|
|
.PP
|
|
A condition variable can be destroyed after its use by calling
|
|
\fBTcl_ConditionFinalize\fR.
|
|
.PP
|
|
The \fBTcl_ConditionNotify\fR, \fBTcl_ConditionWait\fR and
|
|
\fBTcl_ConditionFinalize\fR procedures are defined as empty macros if
|
|
not compiling with threads enabled.
|
|
.SS INITIALIZATION
|
|
.PP
|
|
All of these synchronization objects are self-initializing.
|
|
They are implemented as opaque pointers that should be NULL
|
|
upon first use.
|
|
The mutexes and condition variables are
|
|
either cleaned up by process exit handlers (if living that long) or
|
|
explicitly by calls to \fBTcl_MutexFinalize\fR or
|
|
\fBTcl_ConditionFinalize\fR.
|
|
Thread local storage is reclaimed during \fBTcl_FinalizeThread\fR.
|
|
.SH "SCRIPT-LEVEL ACCESS TO THREADS"
|
|
.PP
|
|
Tcl provides no built-in commands for scripts to use to create,
|
|
manage, or join threads, nor any script-level access to mutex or
|
|
condition variables. It provides such facilities only via C
|
|
interfaces, and leaves it up to packages to expose these matters to
|
|
the script level. One such package is the \fBThread\fR package.
|
|
.SH EXAMPLE
|
|
.PP
|
|
To create a thread with portable code, its implementation function should be
|
|
declared as follows:
|
|
.PP
|
|
.CS
|
|
static \fBTcl_ThreadCreateProc\fR MyThreadImplFunc;
|
|
.CE
|
|
.PP
|
|
It should then be defined like this example, which just counts up to a given
|
|
value and then finishes.
|
|
.PP
|
|
.CS
|
|
static \fBTcl_ThreadCreateType\fR
|
|
MyThreadImplFunc(
|
|
ClientData clientData)
|
|
{
|
|
int i, limit = (int) clientData;
|
|
for (i=0 ; i<limit ; i++) {
|
|
/* doing nothing at all here */
|
|
}
|
|
\fBTCL_THREAD_CREATE_RETURN\fR;
|
|
}
|
|
.CE
|
|
.PP
|
|
To create the above thread, make it execute, and wait for it to finish, we
|
|
would do this:
|
|
.PP
|
|
.CS
|
|
int limit = 1000000000;
|
|
ClientData limitData = (void*)((intptr_t) limit);
|
|
Tcl_ThreadId id; \fI/* holds identity of thread created */\fR
|
|
int result;
|
|
|
|
if (\fBTcl_CreateThread\fR(&id, MyThreadImplFunc, limitData,
|
|
\fBTCL_THREAD_STACK_DEFAULT\fR,
|
|
\fBTCL_THREAD_JOINABLE\fR) != TCL_OK) {
|
|
\fI/* Thread did not create correctly */\fR
|
|
return;
|
|
}
|
|
\fI/* Do something else for a while here */\fR
|
|
if (\fBTcl_JoinThread\fR(id, &result) != TCL_OK) {
|
|
\fI/* Thread did not finish properly */\fR
|
|
return;
|
|
}
|
|
\fI/* All cleaned up nicely */\fR
|
|
.CE
|
|
.SH "SEE ALSO"
|
|
Tcl_GetCurrentThread(3), Tcl_ThreadQueueEvent(3), Tcl_ThreadAlert(3),
|
|
Tcl_ExitThread(3), Tcl_FinalizeThread(3), Tcl_CreateThreadExitHandler(3),
|
|
Tcl_DeleteThreadExitHandler(3), Thread
|
|
.SH KEYWORDS
|
|
thread, mutex, condition variable, thread local storage
|