Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python GTK+ 3 Safe Threading

So what should I run at the beginning of my program to make it thread-safe (or thread-aware as I've read in some places):

from gi.repository import Gtk, Gdk, GLib, GObject
import threading

GLib.threads_init()     # ?
GObject.threads_init()  # YES!
Gdk.threads_init()      # ?

my_app()

def my_threaded_func():
   Glib.idle_add(lambda: some_gui_action())
   Glib.timeout_add(300, lambda: some_gui_action())

t = threading.Thread(target=my_thread_func)
t.daemon = True
t.start()

Gtk.main()

Then, what should I do in my threads? Some kind of lock? Is it safe to use Python's threading library or should I use something in GLib, GObject or Gdk? I know there is a ton of questions/answers/examples out there, but they all contradict each other, are not for Gtk+ 3, or not for Python, or simply incomplete, and even what I considered the official docs for Python GI (http://lazka.github.io/pgi-docs/) does not even mention the existence of GObject.threads_init() and Gdk.threads_init().

like image 264
jpcgt Avatar asked Jan 16 '14 00:01

jpcgt


2 Answers

https://wiki.gnome.org/Projects/PyGObject/Threading

.. but, Gdk.threads_init() is deprecated, and I'd recommmend to:

  • Not call Gdk.threads_init, Gdk.threads_enter/leave at all
  • Use GLib.idle_add instead of Gdk.threads_add_idle (or any other Gdk.threads_* function)
  • Push things touching Gdk/Gtk to the main thread using GLib.idle/timeout_add

Why?:

  • Not calling Gdk.threads_init means there will be no lock, which is OK if you never access GDK from another thread.
  • Gdk.threads_enter does nothing since there is no lock.
  • GLib.idle_add is equal to Gdk.threads_add_idle in this case.

Regarding other libs:

  • Some GI modules can emit certain signals/callbacks in other threads (in GStreamer the GstPlayBin::about-to-finish signal for example); even if you don't use Python threads in your code at all. Gdk/Gtk code can't be called in them directly, use idle_add there as well if needed.
  • Many parts of GLib/GStreamer are thread safe and can be called from other threads.

tl;dr: Only GObject.threads_init(), in threads push all Gtk/Gdk code to the main thread using GLib.idle_add

like image 119
lazka Avatar answered Oct 05 '22 11:10

lazka


Here is a must to read document if anyone is going to use GTK in multithreaded code. https://wiki.gnome.org/Attic/GdkLock

This document really helped me to understand how to run GTK from C as well as from python (through PyGTK just to import gtk in python) in a single process. Though the GDK Lock can be avoided in Linux by XInitThreads() it is not a solution for Windows. The Functions like g_idle_add() or g_timeout_add() are the generic solution to prevent GUI crush. However gdk_threads_enter() and gdk_thread_leave() are not completely useless yet. That document clarifies how to safely use those locks if someone wants to update GUI from different threads or from custom event handler or from g_idle_add() callbacks.

like image 29
abhijit Avatar answered Oct 05 '22 13:10

abhijit