Question

Is there any unambiguous documentation stating whether locks (of any kind) are needed or not for idle_add() / timeout_add() and/or the actual callbacks installed by them?

def work(*args):
  # (1) gtk.gdk.threads_enter() #needed?
  self.ui.change_some_label()
  # (2) gtk.gdk.threads_leave() #?

# (3) gtk.gdk.threads_enter()   #?
gobject.idle_add (work)
# (4) gtk.gdk.threads_leave()   #?

def main():
  gtk.gdk.threads_init()
  #...

Are 1+2 and/or 3+4 necessary? For which pygtk versions does this apply? I am targetting separately 2.12 (on an embedded platform) and 2.24 (on the desktop). Threads are due to gstreamer.

For the underlying C functions g_idle_add(), g_timeout_add() I found a gtk-app-devel discussion that states

If you have called gdk_threads_init then idle and timeout handlers will be run without the gdk thread lock and you will have to add gdk_threads_enter/leave calls yourself if you are doing gui stuff.

... though this is from 2004. I find it amazingly hard to locate clear, specific documentation for either GTK+-2 or for PyGTK.

Many answers on SO endorse scheduling GUI work via idle_add, with no locks / critical sections whatsoever (e.g. GUI not updated from another thread when using PyGtk)

Was it helpful?

Solution

calling g_idle_add() and g_timeout_add() does not need locking: they are thread safe operations, and guarantee that the callback will be called in the GMainContext that is currently spinning the main loop.

the documentation you linked says that the callback will need to acquire the GDK master lock; the callback is invoked by GLib, but the lock is provided by GDK, hence you will need to acquire it explicitly to avoid threads interrupting during the callback emission.

for this reason, the C API provides the gdk_threads_add_idle() and gdk_threads_add_timeout() functions (and their full() variants), which guarantee to invoke your callback with the GDK lock held. PyGTK does not wrap those functions, because it would need to also hold the Python interpreter lock; this means that you will need to remember to call gdk_threads_enter()/gdk_threads_leave() yourself in the callback.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top