I have implemented a countdown timer that has a "Reset" button for cancelling a countdown:
set LAUNCHTIME 5
set message $LAUNCHTIME
set afterId {}
proc countdown {remainingSeconds} {
global afterId message
# **
if {$remainingSeconds > 0} {
set message $remainingSeconds
# **
set afterId [after 1000 [list countdown [expr {$remainingSeconds - 1}]]]
} else {
set message "Takeoff!"
.start configure -state normal
}
}
label .message -textvariable message
button .start -text Start -command {
.start configure -state disabled
countdown $LAUNCHTIME
}
button .reset -text Reset -command {
# Reset timer, message, and button.
after cancel $afterId ;# <- XXX: Could this cause a race condition?
set message $LAUNCHTIME
.start configure -state normal
}
grid .message
grid .start
grid .reset
grid anchor . center
This is what it looks like when the "Start" button is pressed:
Is there a possible race condition when the "Reset" button is pressed while a countdown is occurring? I am worried about the possibility that the "Reset" button is pressed while the program is executing the parts between the double asterisks (**) in the code above. At that point, there is no delayed command that is scheduled to execute, so the "Reset" does not cancel any delayed command. However, right after, a new delayed command will be scheduled to execute (set afterId [after 1000 ...]), even though the user has intended to reset the countdown.
