Then the example, which is waiting for the variable to be set twice,
might use 2 variables instead. Then this could work I think (but I never
say never with these sticky timing problems):
The thread::send manual page includes an example to show the use of the varname parameter for returning and waiting on an -async call. Here's
the example with some extra commented out statements:
set t1 [thread::create]
set t2 [thread::create]
thread::send -async $t1 "set a 1" result
thread::send -async $t2 "set b 2" result
# uncomment these 2 and it will hang
# after 1 {set timervar 1}
# vwait timervar
for {set i 0} {$i < 2} {incr i} {
vwait result
}
Doesn't the above work, *only* because this code doesn't enter the event
loop via a call to vwait (or update)? If I uncomment the after and
vwait, it hangs. So, isn't there an undocumented trap here that should
at least be mentioned in the documentation?
My conjecture is the threads return the result via a thread::send back
to the main thread, and so that goes into the event queue. Anything that activates the event queue before the [vwait result] will set result
before the main thread can vwait on it, and vwait doesn't "queue up"
these signals.
Or am I wrong about how it actually works?
You are overcomplicating things. The variables will only be updated when
the event loop is running. So you can just check if the variable is
already set before you are about to run the vwait. There is no need for
a vwait option.
Even easier may be to use array elements for the result variables and
then vwait on the array:
thread::send -async $t1 {after 4321; set a 1} result(a)
thread::send -async $t2 {after 1234; set b 2} result(b)
while {[array size result] < 2} {
vwait result
puts [array get result]
}
Strangely, the vwait manual page doesn't mention that you can use vwait
on an array and setting any array element will then cause the vwait to return. But in practice that works.
If you don't feel comfortable with this solution for that reason, you
can also set up variable traces on the result variables. Those can fire
in any order.
Schelte.
Am 03.09.21 um 22:20 schrieb ted brown:
The thread::send manual page includes an example to show the use of the
varname parameter for returning and waiting on an -async call. Here's
the example with some extra commented out statements:
set t1 [thread::create]
set t2 [thread::create]
thread::send -async $t1 "set a 1" result
thread::send -async $t2 "set b 2" result
# uncomment these 2 and it will hang
# after 1 {set timervar 1}
# vwait timervar
for {set i 0} {$i < 2} {incr i} {
vwait result
}
Doesn't the above work, *only* because this code doesn't enter the event
loop via a call to vwait (or update)? If I uncomment the after and
vwait, it hangs. So, isn't there an undocumented trap here that should
at least be mentioned in the documentation?
My conjecture is the threads return the result via a thread::send back
to the main thread, and so that goes into the event queue. Anything that
activates the event queue before the [vwait result] will set result
before the main thread can vwait on it, and vwait doesn't "queue up"
these signals.
Or am I wrong about how it actually works?
it should hang when the var "result" is no longer written to
after the "vwait timervar" returns.
What I'd do is
trace the "result" and "timervar" with a proc that increments another variable "touchcount" :-)
Then:
while {$touchcount < 3} {
vwait touchcount
}
you can saveguard this costruct with
after $longtime {incr touchcount 100 }
# test on touchcount >= 100 for determining a timeout condition.
Uwe
* ted brown <tedbrown888@gmail.com>
| On 9/4/2021 12:06 PM, Schelte wrote:
| > You are overcomplicating things. The variables will only be updated
| > when the event loop is running. So you can just check if the
| > variable is already set before you are about to run the vwait. There
| > is no need for a vwait option.
| I don't know how to check for a variable being set to a value unless
| that variable didn't yet exist. So, that would mean one should (or
| must) unset the variable before doing the send.
This sounds much like the classical cond-wait-deadlock...
If there is a value which the variable will definitely not be set to,
you could:
set var ""
thread::send -async $t1 {after 4321; set a 1} var
thread::send -async $t2 {after 1234; set b 2} var
# if var was not yet set, wait for it
if {$var eq ""} {
vwait var
}
R'
unset var
do the thread::send
if {![info exist var]} {
vwait var
}
This is for my "tasks" wrapper/extension of threads. Each wrapped
thread includes all the needed code and shared variables to implement
a single-queue multi-sever model.
* ted brown <tedbrown888@gmail.com>
| set t2 [thread::create]
| unset -nocomplain var1
| unset -nocomplain var2
| thread::send -async $t1 {after 4321; set a 1} var1
| thread::send -async $t2 {after 1234; set b 2} var2
| # ok to do other vwaits or updates here
| after 500 {set var3 1}
| vwait var3
| update
| if {![info exist var1]} {
| vwait var1
| }
| if {![info exist var2]} {
| vwait var2
| }
| puts "var1 = $var1 var2 = $var2"
This indeed is a variation on using conditional vars, which is the
'usual' way of doing this in languages where the concept of 'unset
variables' is not available; check the thread::cond section in the
thread(n) manpage for more.
In TCL you can shortcut this because of the separation of interps/threads/eventloop.
R'
ted brown <tedbrown888@gmail.com> wrote:
This is for my "tasks" wrapper/extension of threads. Each wrapped
thread includes all the needed code and shared variables to implement
a single-queue multi-sever model.
I'm still not sure exactly what it is that you are building, but have
you looked at the 'tpool' module that is part of the threads package?
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 285 |
Nodes: | 16 (2 / 14) |
Uptime: | 29:48:17 |
Calls: | 6,448 |
Files: | 12,050 |
Messages: | 5,254,563 |