FAQ Index - Search - Recent Changes - Everything - Add entry

<< Previous Entry | FAQ Entry 21.3 | Next Entry >>

21.3. Does the Win32 port support threading?

More or less.

The current (and unlikely to change) status of threads on win32 is that you basically can't perform gui operations from a subthread, even with gdk_threads_enter/leave (and any GTK or GDK call should be considered a "gui operation"). Essentially, the X11 and win32 gui/threading models are different, and making gtk work the same on both would be very hard. There is a proposal to solve this problem more fundamentally at [bugzilla.gnome.org]

This isn't entirely bad news, though. Threads on win32 /do/ work in most situations. Be sure to check general tips at [faq.pygtk.org] first

If you need to use signals in a threaded win32 application, you need to make sure that the signal sent to your widget is done from the main thread instead of the subthread. The easiest way to do this is using gobject.idle_add via a wrapperfunction:

  def do_gui_operation(function, *args, **kw):
      def idle_func():
          gtk.threads_enter()
          try:
              function(*args, **kw)
              return False
          finally:
              gtk.threads_leave()
      gobject.idle_add(idle_func)
Now, in your subthread, instead of calling:

  gtk.threads_enter()
  do_gtk_stuff(arg1, arg2)
  gtk.threads_leave()
You should call:

  do_gui_operation(do_gtk_stuff, arg1, arg2)
You don't need to hold the thread lock to call gobject.idle_add (or do_gui_operation) but you do need to acquire it inside the idle function because they are, by default, run without holding the thread lock.

Note also some advice from Alexandre Fayolle, Win32 PyGTK extraordinaire, on older versions of PyGTK:

A trick to get threads to work properly that was sent to the list some time ago (I don't remember who I should credit for it, but it works very well) is to add a timeout function that does a very short sleep, for instance 1e-3 seconds, using timeout_add(...), for instance:

 from gtk import *
 import time
 import sys
 def sleeper():
    time.sleep(.001)
    return 1 # don't forget this otherwise the timeout will be removed

 if __name__== '__main__':
    # do other inits here
    if sys.platform == 'win32':
        timeout_add(400,sleeper)
    mainloop()
You should adjust the value of the period of the timeout so that your app still runs smoothly.

If you want pseudothreads that do not suffer from such problems see: [aspn.activestate.com] [www.gnome.org]

PyGTK FAQ Wizard | PyGTK Homepage | Feedback to faq at pygtk.org