Fernando J. Pereda’s blag

May 20, 2008

Gmandel, Gtk+ and Threads

Filed under: blag — Tags: , , , — Fernando J. Pereda @ 1:18 am

For gmandel (see Chaotic Stuff for more info) I had to add a little GtkProgressBar so that users have a rough estimate of the time it’ll take rendering the fractal.

I wanted to have a clean and easy to study code, so, to avoid threads (that are usually difficult to study for newcomers) I used the following hack to update the progress bar:

static inline void flush_events(void)
    while (gtk_events_pending())

And, with some code to save expose events and relaunch them once the image had been rendered, it worked fine. However, that’s a hack, and the real solution is to fire a new thread to do the rendering work and update the widget when it’s finished. Na├»ve I was.

Gtk+’s documentation states it very clearly: Make sure you protect all calls to Gtk with a gdk_threads_enter(), gdk_threads_leave() pair. With that, you can call Gtk functions from any thread you want and forget about implementing IPC mechanisms to make all the calls from one thread. One of the problems is that the default implementation of the Gdk lock is a non-reentrant mutex, which means you lock it while already holding it (otherwise, you deadlock).

It should be noted that gtk_main() should also be enclosed in an enter-leave which means that functions called by it, can’t try to lock Gdk’s mutex or they’ll deadlock. This is a problem if you are trying to share functions between event handlers and threads. The trick here is to replace that mutex with a couple of functions that lock a reentrant mutex using gtk_threads_set_lock_functions().

What isn’t clear is that gtk_events_pending() will try to acquire Gdk’s lock. For some reason, I forgot to remove the hack that events_flush() was, and had wasted lots of time trying to fix a small, difficult to reproduce, race condition because I was calling gtk_events_pending() while holding the Gdk lock.

So, really, working with threaded applications in Gtk+ is really easy. It is just a matter of protecting calls to Gtk with a critical section. I’m not sure why the documentation isn’t more clear, and the fact that some of the old information floating in the web still advises to only call Gtk from one thread doesn’t really help. Had I started with a threaded version instead of using events_flush() thing would’ve been far easier :)

Bottom line: If something is difficult, working it around won’t make it easier, quite the contrary.

— ferdy

Create a free website or blog at WordPress.com.