I'm using tcl8.4.13 (latest release) with multi-threading in my
C++-application. The application might run several interpreters
(getting commands from a self-made console or a script-file) at same
time.
Now I'd like to allow the user to abort a running script - from outside
or from within the script with my own implementation of "exit" (the
default-one wants to shut down my whole application!?).
So, is there any other way than the brute-force-termination of the
interpreter-thread (I create for each interpreter a seperate thread)?
Or is this actually a possible way without producing memory leaks?
To continue with the script until one of my own commands is execute and
do some voodoo in there to abort the script (as done by other
applications I've seen) would be less comfortable but also an option -
but the question is still: how to abort the script from there, a
user-defined return-code?
Thanx and regards!
Patrik Stellmann
One way to do that is to call [interp delete] on the interpreter. This
cannot be done from the interpreter itself, it has to be done in a
master interpreter. Please look at the bug ticket 495830
(https://sourceforge.net/tracker/index.php?func=detail&aid=495830&group_id=10894&atid=110894)
for a way to do it from the interpreter itself ('suicide').
Please note that you may (and in general will?) get an 'interp deleted'
error on termination.
Two caveats:
(1) I am not sure if you can kill the master interp in a thread in this
way, no time to test it now.
(2) That bug in 8.4 (fixed in 8.5) will allow some currently running
bytecoded commands to keep executing before the interp is deleted, as
shown in the bug report. It is sure to be a very short delay, and I have
trouble imagining how you'd be able to get any important side-effects
from that. But I am not willing to guarantee there aren't any: as shown
in the bug report, it is possible to design things so that some effects
are seen.
HTH
Miguel
--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|
Here's a "voodoo" approach that I find useful in a Tk-based
environment: wrap "update" and use an event handler for the wrapper to
self-modify and abort. A 3-step process is required:
# 1. wrap Tcl's "update" command
rename update _update
proc update {{idletasks ""}} {
if {"$idletasks" eq "idletasks"} {_update idletasks} else {_update}
}
# 2. bind an appropriate event handler to a convenient keystroke,
# say, <Control-period>, in the Tk-based app:
bind all <Control-Key> {+
if {"%K" eq "period"} {
proc update {{idletasks ""}} {
proc update {{idletasks ""}} {
if {"$idletasks" eq "idletasks"} {_update idletasks} else {_update}
}
error "user abort" "user abort"
}
}
}
# 3. use "update" liberally in your code, especially in for-loops.
A useful variant is to enable the event handler in the console
interpreter only:
console eval {
bind .console <Control-Key> {+
if {"%K" eq "period"} {
consoleinterp eval {
proc update {{idletasks ""}} {
proc update {{idletasks ""}} {
if {"$idletasks" eq "idletasks"} {_update idletasks} else
{_update}
}
error "user abort" "user abort"
}
}
}
}
}
You can edit this variant to apply to a different interpreter.
One side effect is that a latent error may be generated if the user
enters the keystroke, but the script terminates for some other reason.
The next encounter of "update" within your session will cause an error.
To remove this possibility, simply re-initialize the wrapper.
This approach requires no globals, avoids conflicts with "bgerror", and
preserves useful info in ::errorInfo, should you need it.
Peter Martin