Tkinter wait_variable problem: hangs at termination

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Russell E. Owen

    Tkinter wait_variable problem: hangs at termination

    I want to support execution of simple user-written scripts in a Tkinter
    application. The scripts should be able to wait for data and such
    without hanging the GUI (and without having to write the script as a
    bunch of asynchronously called subroutines).

    I decided to use Tkinter's wait_variable. I built a "script runner"
    object that has suitable wait methods. Internally each of these methods
    registers a callback that sets a variable when the wait condition is
    satisfied, then calls wait_variable to wait until the variable is set.

    The resulting scripts are simple and seem to work well, e.g.:

    myscript(sr):
    # do some normal python stuff that is fast
    sr.waitForData( ...)
    # more normal fast python stuff
    sr.waitForMS(ti me)
    # etc.

    Unfortunately, if a user closes the root window while wait_variable is
    waiting, the application never fully quits. On my unix box the root
    window closes but the command-line prompt never returns and ^C is
    ignored. The process isn't using excess cpu cycles; it's just not
    listening.

    I have tried registering an atexit handler and adding a __del__ method
    so that the variable being waited on is toggled at shutdown, but it
    makes no difference.

    Here is an example:
    <ftp://ftp.astro.washi ngton.edu/pub/users/rowen/python/WaitBug.py>
    Press "Start" to start the script (which simply prints a number to
    sys.stdout every second, then quits. Close the root window while the
    script is waiting to print the next number, or after pausing the script,
    and you'll see the problem.

    Any suggestions for how to avoid/work around this problem? If it's a
    Tkinter bug I'll report it.

    -- Russell

    P.S. I saw that some perl/Tk users got around a different problem by
    faking wait_variable by running a tight "do one event, see if the wait
    condition is satisfied" loop.

    I don't think Tkinter allows one to execute a single event, and I
    suspect it would be inefficient even if it were possible. I might be
    able to use update (though the nice thing about wait_variable is most of
    the action happens down at the tcl/tk level, presumably making it
    maximally efficient).

    (This is one of those rare times I wish Tkinter worked at the C level
    the way perl's tk interface does.)
  • Peter Otten

    #2
    Re: Tkinter wait_variable problem: hangs at termination

    <veröffentlic ht & per Mail versendet>

    Russell E. Owen wrote:
    [color=blue]
    > I want to support execution of simple user-written scripts in a Tkinter
    > application. The scripts should be able to wait for data and such
    > without hanging the GUI (and without having to write the script as a
    > bunch of asynchronously called subroutines).
    >
    > I decided to use Tkinter's wait_variable. I built a "script runner"
    > object that has suitable wait methods. Internally each of these methods
    > registers a callback that sets a variable when the wait condition is
    > satisfied, then calls wait_variable to wait until the variable is set.
    >
    > The resulting scripts are simple and seem to work well, e.g.:
    >
    > myscript(sr):
    > # do some normal python stuff that is fast
    > sr.waitForData( ...)
    > # more normal fast python stuff
    > sr.waitForMS(ti me)
    > # etc.
    >
    > Unfortunately, if a user closes the root window while wait_variable is
    > waiting, the application never fully quits. On my unix box the root
    > window closes but the command-line prompt never returns and ^C is
    > ignored. The process isn't using excess cpu cycles; it's just not
    > listening.
    >
    > I have tried registering an atexit handler and adding a __del__ method
    > so that the variable being waited on is toggled at shutdown, but it
    > makes no difference.
    >
    > Here is an example:
    > <ftp://ftp.astro.washi ngton.edu/pub/users/rowen/python/WaitBug.py>
    > Press "Start" to start the script (which simply prints a number to
    > sys.stdout every second, then quits. Close the root window while the
    > script is waiting to print the next number, or after pausing the script,
    > and you'll see the problem.
    >
    > Any suggestions for how to avoid/work around this problem? If it's a
    > Tkinter bug I'll report it.
    >
    > -- Russell
    >
    > P.S. I saw that some perl/Tk users got around a different problem by
    > faking wait_variable by running a tight "do one event, see if the wait
    > condition is satisfied" loop.
    >
    > I don't think Tkinter allows one to execute a single event, and I
    > suspect it would be inefficient even if it were possible. I might be
    > able to use update (though the nice thing about wait_variable is most of
    > the action happens down at the tcl/tk level, presumably making it
    > maximally efficient).
    >
    > (This is one of those rare times I wish Tkinter worked at the C level
    > the way perl's tk interface does.)[/color]

    Without any deeper insight in your script - could the following meet your
    needs?

    # instead of atexit.register ():
    def dw():
    self.cancel()
    self._tk.destro y()
    self._tk.protoc ol("WM_DELETE_W INDOW", dw)

    and further down:

    root = Tkinter.Tk()
    ScriptRunner._t k = root

    That way your runner would get notified if the window shall be closed.

    Peter




    Comment

    • Russell E. Owen

      #3
      Re: Tkinter wait_variable hang on exit SOLVED

      In article <ca550b$9n7$07$ 1@news.t-online.com>,
      Peter Otten <__peter__@web. de> wrote:
      [color=blue]
      ><veröffentlich t & per Mail versendet>
      >
      >Russell E. Owen wrote:
      >[color=green]
      >> I want to support execution of simple user-written scripts in a Tkinter
      >> application. The scripts should be able to wait for data and such
      >> without hanging the GUI (and without having to write the script as a
      >> bunch of asynchronously called subroutines).
      >>
      >> I decided to use Tkinter's wait_variable. I built a "script runner"
      >> object that has suitable wait methods...
      >>...
      >> Unfortunately, if a user closes the root window while wait_variable is
      >> waiting, the application never fully quits. On my unix box the root
      >> window closes but the command-line prompt never returns and ^C is
      >> ignored. The process isn't using excess cpu cycles; it's just not
      >> listening.[/color][/color]
      [color=blue]
      >Without any deeper insight in your script - could the following meet your
      >needs?
      >
      > # instead of atexit.register ():
      > def dw():
      > self.cancel()
      > self._tk.destro y()
      > self._tk.protoc ol("WM_DELETE_W INDOW", dw)
      >
      >and further down:
      >
      > root = Tkinter.Tk()
      > ScriptRunner._t k = root
      >
      >That way your runner would get notified if the window shall be closed.[/color]

      This fix does, indeed work! Also, there is an even easier solution: it
      turns out to be sufficient to bind to <Destroy>. The callback sets the
      variable being waited on and the application no longer hangs.

      However, wait_variable proved to unsuitable because if multiple users
      use wait_variable, they stack up. If a new routine executes
      wait_variable while an existing one is waiting, the new routine has to
      fully finish executing before the first one resumes. This is
      understandable in hindsight, but disappointing. As a result:
      - only one script could be run at a time
      - if wait_variable is used elsewhere (and some dialog boxes are reported
      to do so) then that would also pause an executing script

      I ended up implementing user-written scripts as generators, instead. The
      user's script ends up looking like this:
      def myscript(sr):
      yield sr.doCmd(...)
      ...
      yield sr.waitMS(...)

      where sr is a ScriptRunner object. sr's doCmd, waitMS etc. set up a
      termination condition that causes the script generator's next() method
      to be executed, until the script is finished.

      This works fully normally with Tk's event loop. No wait_variable magic
      is involved and multiple scripts can peacefully run at the same time.

      The big problem is that users are likely to forget the "yield"
      statement. To help with this I increment one counter each time a wait
      subroutine begins and another counter each time the script generator is
      executed. Any discrepancy indicates a missing yield.

      -- Russell

      Comment

      Working...