Strange threading behaviour

Dieter Maurer dieter at handshake.de
Thu Jun 21 13:26:59 EDT 2012


Rotwang <sg552 at hotmail.co.uk> writes:

> Hi all, I'm using Python 2.7.2 on Windows 7 and a module I've written
> is acting strangely. I can reproduce the behaviour in question with
> the following:
>
> --- begin bugtest.py ---
>
> import threading, Tkinter, os, pickle
>
> class savethread(threading.Thread):
>     def __init__(self, value):
>         threading.Thread.__init__(self)
>         self.value = value
>     def run(self):
>         print 'Saving:',
>         with open(os.path.join(os.getcwd(), 'bugfile'), 'wb') as f:
>             pickle.dump(self.value, f)
>         print 'saved'
>
> class myclass(object):
>     def gui(self):
>         root = Tkinter.Tk()
>         root.grid()
>         def save(event):
>             savethread(self).start()
>         root.bind('s', save)
>         root.wait_window()
>
> m = myclass()
> m.gui()
>
> --- end bugtest.py ---
>
>
> Here's the problem: suppose I fire up Python and type
>
>>>> import bugtest
>
> and then click on the Tk window that spawns and press 's'. Then
> 'Saving:' gets printed, and an empty file named 'bugfile' appears in
> my current working directory. But nothing else happens until I close
> the Tk window; as soon as I do so the file is written to and 'saved'
> gets printed. If I subsequently type
>
>>>> bugtest.m.gui()
>
> and then click on the resulting window and press 's', then 'Saving:
> saved' gets printed and the file is written to immediately, exactly as
> I would expect. Similarly if I remove the call to m.gui from the
> module and just call it myself after importing then it all works
> fine. But it seems as if calling the gui within the module itself
> somehow stops savethread(self).run from finishing its job while the
> gui is still alive.
>
> Can anyone help?

It looks as if some waiting operation
in the "wait_window" call did not release the GIL (the "Global Interpreter
Lock" which ensures that at most one Python thread can run at a given
time and protects the Python data structures such as the reference counts
and interpreter state).

In this case, you could expect some non-deterministic behaviour.
If your thread is fast enough to finish before the internal
activity inside "wait_window" gets the GIL again,
everything completes immediately; otherwise, things complete
only after the internal waiting ends and Python code is again executed.


It might well be possible that "TKinter" has not been designed for
a multi threaded environment; alternatively, there might be a bug.
If "TKinter" truely supports multithreaded applications, any call
to "tk" would need to release the GIL and any callback into Python
reacquire it. Strange things of the kind you observe could happen
when this is forgotten at a single place.




More information about the Python-list mailing list