Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
thread(n)							     thread(n)

______________________________________________________________________________

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.   Addition-
       ally,  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  si-
	      multaneously  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 re-
	      turned 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  com-
	      mand  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 cre-
	      ated with	-joinable flag results in resource and memory leaks.

	      Threads created by the thread::create cannot be destroyed	force-
	      fully.  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 impossi-
	      ble 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 pos-
	      sible to create initially	preserved threads by using flag	 -pre-
	      served  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 in-
	      crement.	If called with the optional  thread  id,  the  command
	      preserves	the given thread. Otherwise the	current	thread is pre-
	      served.

	      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 sig-
	      nalizes 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.  Com-
	      mand returns the value of	the reference counter after the	decre-
	      ment.   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 nega-
	      tive 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  us-
	      ing  the	-wait,	since this may block the caller	thread indefi-
	      nitely.  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  op-
	      tion  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  cur-
	      rent 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 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  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  in-
	      tervening	 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 de-
	      fault 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  re-
	      sult  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 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  for
	      threads  created without a startup script. Threads can enter the
	      event loop explicitly by calling thread::wait or any other rele-
	      vant Tcl/Tk command, like	update,	vwait, etc.

	      Optional varname specifies name of the variable to store the re-
	      sult of the script. Without the -async flag, the command returns
	      the  evaluation  code,  similarly	to the standard	Tcl catch com-
	      mand. If,	however, the -async flag is specified, the command re-
	      turns 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 re-
	      sults 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, in-
	      termingled 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 pack-
	      age 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 re-
	      sulting script under the mutex protection. If no mutex is	speci-
	      fied  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 fcon-
	      figure 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  un-
	      available	to evaluate additional scripts.

       thread::transfer	id channel
	      This moves the specified channel from the	current	thread and in-
	      terpreter	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 con-
	      nection 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  un-
	      til  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 ac-
	      cess 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  mu-
	      texes,  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 thread::mutex	command	supports following subcommands and op-
	      tions:

	      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?	 argu-
		     ment was specified, the command creates the exclusive mu-
		     tex. With the ?-recursive?	argument, the command  creates
		     a recursive mutex.

	      thread::mutex destroy mutex
		     Destroys the mutex. Mutex should be in unlocked state be-
		     fore 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 per-
	      formance 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	refer-
		     ence 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 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 conjunction with an exclusive mutex.	If you
	      attempt to use other type	of mutex in conjunction	with the  con-
	      dition 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	refer-
		     ence 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	condi-
		     tion 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 op-
		     tional 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 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 accomplished
		     by	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 $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	condi-
		     tion 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" abstrac-
       tion 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 re-
       quests 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 sup-
       ported.

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

KEYWORDS
       events, message passing,	mutex, synchronization,	thread

Tcl Threading			      2.8			     thread(n)

NAME | SYNOPSIS | DESCRIPTION | COMMANDS | DISCUSSION | SEE ALSO | KEYWORDS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=thread&manpath=FreeBSD+12.2-RELEASE+and+Ports>

home | help