I am trying to run multiple background threads in a gtk app.
I followed this tutorial to implement thread safe gtk application gtk-threads. However, when I implement the threading using GLib.idle_add
it seems to block the main loop.
main.py
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
from threads import run_in_thread_gtk
import random
window = Gtk.Window()
main_box = Gtk.Box()
list_box = Gtk.ListBox()
button = Gtk.Button(label='update')
button2 = Gtk.Button(label='test button')
main_box.pack_start(list_box, True, True, 0)
main_box.pack_start(button, False, False, 0)
main_box.pack_start(button2, False, False, 0)
window.add(main_box)
window.show_all()
def update_rows(*args, **kwargs):
for child in list_box.get_children():
list_box.remove(child)
for i in range(10):
list_box.add(Gtk.Label(label=f"Row {random.random()}"))
from time import sleep
sleep(2)
list_box.show_all()
return False
button.connect('clicked', run_in_thread_gtk, update_rows)
Gtk.main()
thread.py
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib
from threading import Thread, BoundedSemaphore
semaphore = BoundedSemaphore(10)
def run_in_thread_gtk(widget, func, *args, **kwargs):
global semaphore
thread = Thread(target=thread_func_wrapper, args=(func, semaphore,))
thread.start()
return True
def thread_func_wrapper(func, semaphore):
with semaphore:
GLib.idle_add(func) # I use GLib.idle_add here
Use the previous code it seems that the GLib.idle_add
blocks the main loop and the UI freeze. However, when I change the code the following code it works fine.
main.py
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
from threads import run_in_thread_gtk
import random
window = Gtk.Window()
main_box = Gtk.Box()
list_box = Gtk.ListBox()
button = Gtk.Button(label='update')
button2 = Gtk.Button(label='test button')
main_box.pack_start(list_box, True, True, 0)
main_box.pack_start(button, False, False, 0)
main_box.pack_start(button2, False, False, 0)
window.add(main_box)
window.show_all()
def update_rows(*args, **kwargs):
for child in list_box.get_children():
GLib.idle_add(list_box.remove, child)
for i in range(10):
GLib.idle_add(list_box.add, Gtk.Label(label=f"ROW {random.random()}"))
from time import sleep
sleep(2)
GLib.idle_add(list_box.show_all)
return False
button.connect('clicked', run_in_thread_gtk, update_rows)
Gtk.main()
thread.py
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib
from threading import Thread, BoundedSemaphore
semaphore = BoundedSemaphore(10)
def run_in_thread_gtk(widget, func, *args, **kwargs):
global semaphore
thread = Thread(target=thread_func_wrapper, args=(func, semaphore,))
thread.start()
return True
def thread_func_wrapper(func, semaphore):
with semaphore:
func() # No GLib.idle_add
The difference between the codes is the place where I used GLib.idle_add.