thread: -eventmark and send -async describes how these two features can interact to cause a deadlock.
Reported here .
PYK 2015-04-12:
thread::configure $thread -eventmark ... limits the number of asynchronous calls to the thread. If thread A and thread B are configured with an -eventmark, and thread A uses the variant of thread::send -async that specifies a variable in which to store the result of the call, a deadlock can occcur if As -eventmark limit is reached in the meantime. Apparently, the response from B to A that stores the result in the specified variable is subject to the queue limit of A. Because asynchronous calls become blocking when a thread's queue limit is reached, A ends up blocked in an -async call to B, which in turn is blocked waiting for As queue to die down so that it can write its response.
I think this is a bug because with -eventmark, the intent is normally to throttle incoming work, and not to limit responses to calls to other threads, and it can be a real head-scratcher when such a deadlock occurs in a non-trivial threaded program.
In versions of thread that behave like this, the rule of the to is to not execute thread::send -async ... varname] from a thread that has been configured with a non-zero -eventmark value.
Here's a script that illustrates the issue:
#! /bin/env tclsh package require Thread set consumer [thread::create { proc eat value { puts [list [thread::id] receive $value] } thread::wait }] thread::configure $consumer -eventmark 10 set filter [thread::create { proc eat value { variable consumer # This command causes the threads to hang. thread::send -async $consumer [list eat [expr {$value * 2}]] [namespace current]::reply # Replace the previous command with this one, and the deadlock resolves. #thread::send -async $consumer [list eat [expr {$value * 2}]] } thread::wait }] thread::send $filter [list variable consumer $consumer] thread::configure $filter -eventmark 10 for {set i 0} {$i < 50} {incr i} { set thread [thread::create { proc go {} { variable filter set value 1 while 1 { incr value 2 #puts [list sending $value to $filter] thread::send -async $filter [list eat $value] } } thread::wait }] thread::send -async $thread [list variable filter $filter] thread::send -async $thread {after 0 [list after idle go]} } vwait forever