===================================================================
RCS file: RCS/faq20.006.htp,v
retrieving revision 1.3
retrieving revision 1.9
diff -u -r1.3 -r1.9
--- faq20.006.htp 2003/05/18 13:50:39 1.3
+++ faq20.006.htp 2005/08/29 17:48:07 1.9
@@ -1,18 +1,78 @@
-Title: 20.6. I am using a separate thread to run my code, but the UI is still unresponsive.
-Last-Changed-Date: Sun May 18 10:50:39 2003
-Last-Changed-Author: Christian Reis
-Last-Changed-Email: kiko@async.com.br
-Last-Changed-Remote-Host: 200-148-103-52.dsl.telesp.net.br
-Last-Changed-Remote-Address: 200.148.103.52
+Title: 20.6. I am using a separate thread to run my code, but the application (or the UI) hangs.
+Last-Changed-Date: Mon Aug 29 14:48:07 2005
+Last-Changed-Author: Gustavo Carneiro
+Last-Changed-Email: gjc@inescporto.pt
+Last-Changed-Remote-Host:
+Last-Changed-Remote-Address: 82.155.39.158
+
+There are a couple of hitches you can run into when trying to use threading and PyGTK together. For starters, if you are using threads, no matter if you are doing PyGTK calls from a separate thread or not, you *must* compile PyGTK with --enable-threads.
+
+Now there are two approaches for threads in PyGTK:
+
+1. Allow only the main thread to touch the GUI (gtk) part, while letting other threads do background work. For this to work, first call
+ gobject.threads_init()
+at applicaiton initialization. Then you launch your threads normally, but make sure the threads never do any GUI tasks directly. Instead, you use gobject.idle_add to schedule GUI task to executed in the main thread. Example:
+
+ import threading
+ import time
+ import gobject
+ import gtk
+
+ gobject.threads_init()
+
+ class MyThread(threading.Thread):
+ def __init__(self, label):
+ super(MyThread, self).__init__()
+ self.label = label
+ self.quit = False
+
+ def update_label(self, counter):
+ self.label.set_text("Counter: %i" % counter)
+ return False
+
+ def run(self):
+ counter = 0
+ while not self.quit:
+ counter += 1
+ gobject.idle_add(self.update_label, counter)
+ time.sleep(0.1)
+
+ w = gtk.Window()
+ l = gtk.Label()
+ w.add(l)
+ w.show_all()
+ w.connect("destroy", lambda _: gtk.main_quit())
+ t = MyThread(l)
+ t.start()
+
+ gtk.main()
+ t.quit = True
-There are a couple of hitches you can run into when trying to use threading and PyGTK together. For starters, if you are using threads, no matter if you are doing PyGTK calls from a separate thread or not, you *must* compile PyGTK with --enable-threads *and* call
- gtk.threads_init()
+2. Allow any thread to do GUI stuff. Warning: people doing win32 pygtk programming have said that having non-main threads doing GUI stuff in win32 doesn't work. So this programming style is really not recommended.
+
+Anyway, to make this work, start by calling:
+ gtk.gdk.threads_init()
at startup. Failing to do this will make PyGTK never release the python threading lock. At least Debian's packages are compiled properly, so it's a matter of using that call.
-John K. Luebs reminds you: *don't forget gtk.threads_enter() and gtk.threads_leave()* when accessing gtk code if you want your application to actually work threaded.
+Then you have to wrap your main loop with gtk.threads_enter()/gtk.threads_leave(), like this:
+
+ gtk.threads_enter()
+ gtk.main()
+ gtk.threads_leave()
+
+Your threads code must, before touching any gtk functions or widgets, call gtk.threads_enter(), and after gtk.threads_leave(), for example:
+ ...
+ gtk.threads_enter()
+ try:
+ myentry.set_text("foo")
+ finally:
+ gtk.threads_leave()
+ ...
+
+Also, keep in mind that signal handlers don't need gtk.threads_enter/leave(). There are other concerns, see http://developer.gnome.org/doc/API/2.0/gdk/gdk-Threads.html.
-It's been suggested that you should really make calls using idle_add() from other threads, to make sure that all PyGTK calls run in the thread where the mainloop is running (idle_add()ed calls are processed by the mainloop itself). While not strictly necessary (I think) it should probably avoid some hidden bugs.
+Cedric Gustin posted a short example of threaded code at http://www.daa.com.au/pipermail/pygtk/2003-August/005626.html -- it's a good building block for a more complex threaded application.
Finally, if you are writing a C extension module, remember that you need to protect calls that potentially lock the thread with Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.