有时,我们需要等待某个操作的完成。这里的操作可以用一个Tcl命令来代替。使用 trace 和 vwait 可以完成这个事情。
#-------------------------------------------
# Usage:
# use trace to wait some command to finish
#-------------------------------------------
namespace eval ::noyesno::testing {
proc _traceProc { args } {
set name [lindex $args 0 0]
set op [lindex $args end]
set waitVar [namespace current]::[regsub -all {::} $name "__"]
set time [clock format [clock seconds] -format "%H:%M:%S"]
switch $op {
"enter" { puts "DEBUG: $time $args" }
"leave" {
incr $waitVar
puts "DEBUG: $time $args"
}
}
}
proc waitmgr { op name {val 0}} {
set waitVar [namespace current]::[regsub -all {::} $name "__"]
switch $op {
"init" {
set $waitVar 0
puts "DEBUG: install wait for $name"
trace add execution $name leave [namespace current]::_traceProc
trace add execution $name enter [namespace current]::_traceProc
}
"remove" {
trace remove execution $name leave [namespace current]::_traceProc
trace remove execution $name enter [namespace current]::_traceProc
unset $waitVar
}
"set" {
set $waitVar $val
}
}
}
proc wait { name {sec {4000}} {expect ""}} {
set waitVar [namespace current]::[regsub -all {::} $name "__"]
if {$expect != "" && [set $waitVar] == $expect} {
puts "DEBUG: already finished"
return
}
puts "DEBUG: trace start: $name = [set $waitVar]"
after $sec set $waitVar -1
vwait $waitVar
after cancel set $waitVar -1
if { [set $waitVar] < 0 } {
puts "INFO: **TIMEOUT** wait $name = [set $waitVar]"
} else {
puts "INFO: **OK** wait $name = [set $waitVar]"
}
return $waitVar
}
}
# Usage Demo
proc proc_hello {args} {puts "inside proc_hello"}
after 2000 proc_hello
after 4000 proc_hello
::noyesno::testing::waitmgr init proc_hello
::noyesno::testing::wait proc_hello 3000
::noyesno::testing::wait proc_hello 3000 2
after 5000 proc_hello
::noyesno::testing::wait proc_hello 3000