📄 00000003.htm
字号:
<HTML><HEAD> <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人: cybergene (基因~也许以后~~), 信区: Linux <BR>标 题: Tcl Threading Model <BR>发信站: BBS 水木清华站 (Thu Dec 14 15:59:19 2000) <BR> <BR> <BR>Tcl Threading Model <BR> <BR>TclPro Extensions | Wrap TclPro | Compile Tcl | Stub Libraries | Threads <BR> | Windows Extensions | Regular Expressions | I18N <BR> <BR>This page describes the model Tcl uses for multi-threading, and it gives <BR> an overview of the APIs available at the Tcl and C level. The Thread <BR>Extension exposes the threading facilities described here to the Tcl <BR>script level. <BR>One Thread Per Interpreter <BR>Tcl lets you have one or more Tcl interpreters (e.g., created with <BR>Tcl_CreateInterp()) in each operating system thread. However, each <BR>interpreter is tightly bound to its OS thread and errors will occur if <BR>you let more than one thread call into the same interpreter (e.g., <BR>with Tcl_Eval). <BR>Communication Among Threads <BR>Tcl scripts in different threads can communicate by posting scripts onto <BR> the event queue of an interpreter in a different thread. This can be <BR>synchronous, where you wait for the result, or asynchronous, where <BR>your thread does not wait for the other thread to evaluate its script. <BR>The 2.1 version of the Thread Extension provides shared variables, <BR>mutexes, and condition variables so you can enjoy all the benefits, <BR>perils, and pitfalls of threaded programming. Also, if you use this <BR>extension with the new 8.4 releases you can transfer I/O channels <BR>between threads. <BR> <BR>The Thread Package <BR>By default, Tcl is still compiled without thread support and without <BR>script-level access to threads. To use threads you need to can use the <BR>testthread command that was added to tcltest for the Tcl 8.1 test suite. <BR> This was turned into its own extension, Thread, in conjunction with the <BR> Tcl 8.3.1 release. There is also a mkThread extension created by <BR>Michael Kraus. So, now you can just build Tcl 8.3 (or 8.4) with <BR>threads enabled and load the thread extension. <BR>The Thread 2.1 manual page. <BR> <BR>The C API <BR>If you maintain an extension, you'll need to use the C APIs to make your <BR> extension thread safe. Tcl provides mutex locks, condition variables <BR>for synchronization, and thread-local storage to help manage data <BR>structures. <BR>If you are making old code thread safe, then you can focus your <BR>attention on the global data structures. You'll either need to serialize <BR> all thread access by putting a Tcl_MutexLock and Tcl_MutexUnlock call <BR>around all accesses to the variable, or you may be able to move the data <BR> structure into "thread local storage". <BR> <BR>A great source of examples is the Tcl and Tk source code itself. The <BR>following are examples taken from the sources. <BR> <BR>Mutex Variable Example <BR>The tclEvent.c file maintains a global list of exit handlers. Access <BR>to this list is serialized with a mutex lock. The TCL_DECLARE_MUTEX <BR>macro declares a mutex variable if threading is enabled, otherwise it <BR>does nothing. <BR>static ExitHandler *firstExitPtr = NULL; <BR>TCL_DECLARE_MUTEX(exitMutex) <BR> <BR>Later, in the code that references firstExitPtr: <BR> <BR>Tcl_MutexLock(&exitMutex); <BR>exitPtr->nextPtr = firstExitPtr; <BR>firstExitPtr = exitPtr; <BR>Tcl_MutexUnlock(&exitMutex); <BR> <BR>The Tcl_MutexLock and Tcl_MutexUnlock calls are also macros that <BR>expand into nothing unless you configure with --enable-threads. <BR>Thread Local Storage / ThreadSpecificData <BR>In many cases it is possible to have storage that is private to a thread <BR> instead of shared among threads. Access to this is cheaper because <BR>you do not need to synchronize. For example, Tcl keeps a list of I/O <BR>channels that are opened by a particular thread. As there is no <BR>sharing among interpreters in different threads, this information can be <BR> managed by each thread independently. <BR>If you look in the Tcl sources for <BR> <BR> <BR>typedef struct ThreadSpecificData <BR> <BR>you will find several examples. These are per-file declarations of the <BR>thread-local variables used in that file. For example, in tclIO.c, <BR> <BR>typedef struct ThreadSpecificData { <BR> <BR> /* <BR> * This variable holds the list of nested ChannelHandlerEventProc <BR> * invocations. <BR> */ <BR> NextChannelHandler *nestedHandlerPtr; <BR> <BR> /* <BR> * List of all channels currently open. <BR> */ <BR> Channel *firstChanPtr; <BR> <BR> /* <BR> * Static variables to hold channels for stdin, stdout and stderr. <BR> */ <BR> Tcl_Channel stdinChannel; <BR> int stdinInitialized; <BR> Tcl_Channel stdoutChannel; <BR> int stdoutInitialized; <BR> Tcl_Channel stderrChannel; <BR> int stderrInitialized; <BR> <BR>} ThreadSpecificData; <BR> <BR>static Tcl_ThreadDataKey dataKey; <BR> <BR>Each block of thread specific data is associated with a thread "data <BR>key", which is an identifier for this particular block of thread <BR>specific data. Each thread will use the same identifier to get its own <BR>private copy of those variables. It works like this (e.g., in <BR>TclFinalizeIOSubsystem): <BR> <BR>void <BR>TclFinalizeIOSubsystem() <BR>{ <BR> ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); <BR> Channel *chanPtr; /* Iterates over open channels. <BR> */ <BR> Channel *nextChanPtr; /* Iterates over open channels. <BR> */ <BR> <BR> <BR> for (chanPtr = tsdPtr->firstChanPtr; chanPtr != (Channel *) NULL; <BR> chanPtr = nextChanPtr) { <BR> nextChanPtr = chanPtr->nextChanPtr; <BR> <BR> /* code omitted */ <BR> } <BR>} <BR> <BR>Condition Variables <BR>Condition variables are associated with a Mutex lock. The mutex is <BR>automatically released when you wait on a condition variable, and the <BR>mutex is automatically aquired when you unblock from waiting. The <BR>typical patterns of use are: <BR> <BR>Tcl_MutexLock(&myMutex); <BR> <BR>while (condition_is_false) { <BR> Tcl_ConditionWait(&myConditionVariable, &myMutex, NULL /* no <BR>timeout */); <BR>} <BR> <BR>Tcl_MutexUnlock(&myMutex); <BR> <BR>and <BR> <BR>Tcl_MutexLock(&myMutex); <BR>/* set shared state */ <BR>Tcl_ConditionNotify(&myConditionVariable); <BR>Tcl_MutexUnlock(&myMutex); <BR> <BR>Thread C API documentation <BR> <BR>Allocation and Cleanup Issues <BR>The Mutex, Condition Variable, and Thread Local Storage structures in <BR>Tcl are "self-initializing". For example, there is Tcl_MutexLock and <BR>Tcl_MutexUnlock, but no Tcl_MutexInit. Similarly, the first time a <BR>thread fetches a block of thread-specific data, it is automatically <BR>allocated and initialized to all zeros. <BR>These objects are also cleaned up automatically when a thread is <BR>terminated. The thread-specific data is cleaned up early, right after <BR>the per-thread exit handlers are called. If you need to clean up <BR>information associated with thread specific data, use a per-thread <BR>exit handler to do it. <BR> <BR>Reader's Comments <BR>The following commands for the thread extension v2.1 haven't been <BR>documented yet: <BR>thread::mutex, <BR>thread::cond, <BR>thread::sv_get, <BR>thread::sv_exists, <BR>thread::sv_set, <BR>thread::sv_incr, <BR>thread::sv_append, <BR>thread::sv_lappend, <BR>thread::sv_array, <BR>thread::sv_unset <BR> <BR> <BR>sv_* means shared variable <BR> <BR>-- David Gravereaux, September 15 18:35:05, 2000 <BR> <BR> <BR> <BR> <BR> <BR>-- <BR> 桃花坞里桃花庵,桃花庵下桃花仙;桃花仙人种桃树,又摘桃花卖酒钱。 <BR> 酒醒只在花前坐,酒醉换来花下眠;半醒半醉日复日,花落花开年复年。 <BR> 但愿老死花酒间,不愿鞠躬车马前;车尘马足富者趣,酒盏花枝贫者缘。 <BR> 若将富贵比贫贱,一在平地一在天;若将贫贱比车马,他得驱驰我得闲。 <BR> 别人笑我忒疯癫,我笑他人看不穿;不见五陵豪杰墓,无花无酒锄做田。 <BR> <BR> <BR>※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.204.7.234] <BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -