I have a two-thread application: GUI, and some background work. I’m trying to send requests to the main thread to do GUI updates (move a progress bar), but it doesn’t seem to work. I’ve boiled it down to a really minimal example:
import pygtk
pygtk.require('2.0')
import glib
import gtk
import threading
import sys
import time
def idle():
sys.stderr.write('Hello from another world.\n')
sys.stderr.flush()
gtk.main_quit()
def another_thread():
time.sleep(1)
glib.idle_add(idle)
thread = threading.Thread(target=another_thread)
thread.start()
gtk.main()
This should, I thought, print something to standard error from the main/GUI thread, but nothing happens. And it doesn’t quit, either, so gtk.main_quit isn’t being called.
Also, adding more output to stderr acts weirdly. If I change the thread’s function to:
sys.stderr.write('----\n')
sys.stderr.write('----\n')
sys.stderr.flush()
sys.stderr.write('After.\n')
sys.stderr.flush()
I see 1, sometimes 2 lines out output. It looks like some kind of race condition with the main thread entering gtk.main, but I don’t know why this would be.
The following makes the above work for me:
A call to
gtk.gdk.threads_init()before doing anything else: before starting threads, before enteringgtk.main(). I think in reality, this only needs to be called before enteringgtk.main(), but it is easy enough to call it while everything is single threaded and simple.In the idle callback (
idle, in the example), a call togtk.gdk.threads_enter()before GTK stuff (easy to do just at the top of the function), and a call togtk.gdk.threads_leave(), before the end of the function.gtk.gdk.threads_init()seems to also tell PyGTK not hold the GIL when it goes to sleep – I think I was missing some output from the aux. thread in the example just because the sleeping main thread (sleeping ingtk.main()) was still holding the GIL.gtk.gdk.threads_init(), as far as I can tell, instills good mojo into PyGTK and GTK+. Because of this,gtk.gdk.threads_init()is needed even if you launch a thread that doesn’t touch GTK+, doesn’t do anything with glib, gobject, etc., just does basic computation.