focal (3) thread.3tcl.gz

Provided by: tcl-thread_2.8.5-1_amd64 bug

NAME

       thread - Extension for script access to Tcl threading

SYNOPSIS

       package require Tcl  8.4

       package require Thread  ?2.8?

       thread::create ?-joinable? ?-preserved? ?script?

       thread::preserve ?id?

       thread::release ?-wait? ?id?

       thread::id

       thread::errorproc ?procname?

       thread::cancel ?-unwind? id ?result?

       thread::unwind

       thread::exit ?status?

       thread::names

       thread::exists id

       thread::send ?-async? ?-head? id script ?varname?

       thread::broadcast script

       thread::wait

       thread::eval ?-lock mutex? arg ?arg ...?

       thread::join id

       thread::configure id ?option? ?value? ?...?

       thread::transfer id channel

       thread::detach channel

       thread::attach channel

       thread::mutex

       thread::mutex create ?-recursive?

       thread::mutex destroy mutex

       thread::mutex lock mutex

       thread::mutex unlock mutex

       thread::rwmutex

       thread::rwmutex create

       thread::rwmutex destroy mutex

       thread::rwmutex rlock mutex

       thread::rwmutex wlock mutex

       thread::rwmutex unlock mutex

       thread::cond

       thread::cond create

       thread::cond destroy cond

       thread::cond notify cond

       thread::cond wait cond mutex ?ms?

________________________________________________________________________________________________________________

DESCRIPTION

       The thread extension creates threads that contain Tcl interpreters, and it lets you send scripts to those
       threads for evaluation.  Additionally, it provides script-level access to  basic  thread  synchronization
       primitives, like mutexes and condition variables.

COMMANDS

       This  section  describes  commands for creating and destroying threads and sending scripts to threads for
       evaluation.

       thread::create ?-joinable? ?-preserved? ?script?
              This command creates a thread that  contains  a  Tcl  interpreter.   The  Tcl  interpreter  either
              evaluates the optional script, if specified, or it waits in the event loop for scripts that arrive
              via the thread::send command. Both of them would take place  simultaneously  with  the  return  of
              command  thread::create  to the caller thread.  Neither the caller is waiting for the finishing of
              optional script, nor the result, if any, of the script is returned to the caller.  The  result  of
              thread::create  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 thread::release command below).

              If  the  optional script argument contains the thread::wait command the thread will enter into the
              event loop. If such command is not found  in the script the thread will run the script 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.

              Using flag -joinable it is possible to create a joinable thread, i.e. one upon whose exit  can  be
              waited  upon  by  using  thread::join  command.   Note  that failure to join a thread created with
              -joinable flag results in resource and memory leaks.

              Threads created by the thread::create cannot be destroyed forcefully. Consequently,  there  is  no
              corresponding  thread destroy command. A thread may only be released using the thread::release 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
              script argument, following the thread::wait command. If this was the last command in  the  script,
              as usually the case, the thread will exit.

              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 thread::wait 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:

                  # You should never do ...
                  set tid [thread::create {
                      package require Http
                      thread::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  matching  thread::release  call, the thread will jump out of the thread::wait and
              continue to execute commands following. It will enter vwait command and wait endlessly for events.
              There is no way 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  thread::preserve  and  decremented  by  a   call   to
              thread::release  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  initially  preserved  threads by using flag -preserved of the thread::create
              command. Threads created with this flag have the initial value  of  the  reference  counter  of  1
              (one), and are thus initially marked reserved.

       thread::preserve ?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  the
              increment.   If  called  with  the  optional  thread  id,  the command preserves the given thread.
              Otherwise the current thread is preserved.

              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.

       thread::release ?-wait? ?id?
              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 id,  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 thread::release
              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.

              Optional  flag  -wait  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  -wait,  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  -joinable
              option of the thread::create command and the thread::join to wait for thread to exit.

       thread::id
              This command returns the ID of the current thread.

       thread::errorproc ?procname?
              This command sets a handler for errors that occur in scripts sent asynchronously, using the -async
              flag of the thread::send 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 procname is called in the interpreter that invoked the thread::errorproc  command.  The
              procname is called like this:

                  myerrorproc thread_id errorInfo

       thread::cancel ?-unwind? id ?result?
              This command requires Tcl version 8.6 or higher.

              Cancels  the  script  being evaluated in the thread given by the id parameter. Without the -unwind
              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
              -unwind 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 result is present, it will be used  as  the  error  message  string;  otherwise,  a
              default error message string will be used.

       thread::unwind
              Use of this command is deprecated in favour of more advanced thread reservation system implemented
              with thread::preserve and  thread::release  commands.  Support  for  thread::unwind  command  will
              disappear in some future major release of the extension.

              This  command  stops a prior thread::wait command. Execution of the script passed to newly created
              thread will continue from the thread::wait command. If thread::wait 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.

       thread::exit ?status?
              Use of this command is deprecated in favour of more advanced thread reservation system implemented
              with  thread::preserve  and  thread::release  commands.  Support  for  thread::exit  command  will
              disappear in some future major release of the extension.

              This command forces a thread stuck in  the  thread::wait  command  to  unconditionally  exit.  The
              thread's  exit status defaults to 666 and can be specified using the optional status argument. The
              execution of thread::exit command is guaranteed to leave the program memory  in  the  inconsistent
              state,  produce  memory leaks and otherwise affect other subsystem(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.

       thread::names
              This  command  returns a list of thread IDs. These are only for threads that have been created via
              thread::create command.  If your application creates other threads at the C level,  they  are  not
              reported by this command.

       thread::exists id
              Returns  true  (1)  if  thread given by the id parameter exists, false (0) otherwise. This applies
              only for threads that have been created via thread::create command.

       thread::send ?-async? ?-head? id script ?varname?
              This command passes a script to another thread and, optionally,  waits  for  the  result.  If  the
              -async  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 thread::wait or any other relevant Tcl/Tk command, like update,  vwait,
              etc.

              Optional  varname  specifies  name  of the variable to store the result of the script. Without the
              -async flag, the command returns the evaluation code, similarly to the standard Tcl catch command.
              If,  however,  the  -async flag is specified, the command returns immediately and caller can later
              vwait on ?varname? to get the result of the passed script

                  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
                  }

              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.

              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
              ?-head? 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.

       thread::broadcast script
              This command passes a script to all threads created by the package for execution. It does not wait
              for response from any of the threads.

       thread::wait
              This enters the event loop so a thread can receive messages from the  thread::send  command.  This
              command  should only be used within the script passed to the thread::create. 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 thread::wait 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
                  }]

       thread::eval ?-lock mutex? arg ?arg ...?
              This  command  concatenates  passed  arguments  and evaluates the resulting script under the mutex
              protection. If no mutex is specified by using the ?-lock mutex? optional  argument,  the  internal
              static mutex is used.

       thread::join id
              This  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.

       thread::configure 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  fconfigure  configures  some  Tcl  channel  options.  Options  currently
              supported are: -eventmark and -unwindonerror.

              When  -eventmark  is provided with a value greater than 0 (zero), that value is the maximum number
              of asynchronously posted scripts that may be pending for the thread.  thread::send  -async  blocks
              until the number of pending scripts in the event loop drops below the -eventmark value.

              When  -unwindonerror  is  provided  with  a  value of true, an error result in a script causes the
              thread to unwind, making it unavailable to evaluate additional scripts.

       thread::transfer id channel
              This 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 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
              thread::send  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.

              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 socket 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
                  }

       thread::detach channel
              This 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 state
              until  some  other  (or  the  same)  thread  attaches  the  channel  again  with   thread::attach.
              Restrictions: same as for transferring shared channels with the thread::transfer command.

       thread::attach channel
              This  attaches  the  previously  detached  channel  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 actually 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.

       thread::mutex
              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.

              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 thread::mutex command supports following subcommands and options:

              thread::mutex create ?-recursive?
                     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 ?-recursive? argument was  specified,
                     the  command  creates  the  exclusive  mutex.  With  the ?-recursive? argument, the command
                     creates a recursive mutex.

              thread::mutex destroy 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.

              thread::mutex lock mutex
                     Locks  the mutex. 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.

              thread::mutex unlock mutex
                     Unlocks the mutex so some other thread may lock it again.  Attempt to  unlock  the  already
                     unlocked mutex will throw Tcl error.

       thread::rwmutex
              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 performance 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 thread::rwmutex command supports following subcommands and options:

              thread::rwmutex create
                     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.

              thread::rwmutex destroy mutex
                     Destroys the reader/writer mutex. If the mutex is already locked,  attempt  to  destroy  it
                     will throw Tcl error.

              thread::rwmutex rlock mutex
                     Locks  the mutex for reading. More than one thread may read-lock the same mutex at the same
                     time.

              thread::rwmutex wlock mutex
                     Locks 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.

              thread::rwmutex unlock mutex
                     Unlocks  the  mutex  so  some  other  thread  may lock it again.  Attempt to unlock already
                     unlocked mutex will throw Tcl error.

       thread::cond
              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  conjunction  with  an
              exclusive  mutex.  If  you  attempt  to  use other type of mutex in conjunction with the condition
              variable, a Tcl error will be thrown.

              The command supports following subcommands and options:

              thread::cond create
                     Creates the condition variable and returns it's opaque handle.  This handle should be  used
                     for any future reference to newly created condition variable.

              thread::cond destroy cond
                     Destroys  condition  variable cond. Extreme care has to be taken that nobody is using (i.e.
                     waiting on) the condition variable, otherwise unexpected errors may happen.

              thread::cond notify cond
                     Wakes up all threads waiting on the condition variable cond.

              thread::cond wait 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 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 cond, the command releases mutex.  Before returning 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  ms  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.

                     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:

                         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

                     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).

DISCUSSION

       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, vwait 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 supported.

SEE ALSO

       http://www.tcl.tk/doc/howto/thread_model.html, tpool, tsv, ttrace

KEYWORDS

       events, message passing, mutex, synchronization, thread