Hi, here is my short summery of how to use gtk with threads, ordered by the main problems to be worked around. I aimed to find a small set of *general* rules to follow rather than solutions for individual cases. So this guides shall turn gtk's thread awareness into thread safety--for those who need that.
All this has been tested and works for me--but may have some flaws, so especially if you have doubts this was a reasonable approach please comment! :-) (1) SYNCHRONIZE THREADS Nothing new: All access to gtk needs to be wrapped into gdk_threads_enter/leave function pairs. (2) DEADLOCK WHILE CONSTRUCTING COMPLEX WINDOWs? Even when you follow rule (1) you might freeze gtk. This happens easily when you e.g. write functions to create widgets or groups of it and then use this functions in higher contexts: So you call gdk_threads_enter() twice before gdk_threads_leave(). A general and most comfortable way for a later easy use of gtk is using recursive mutexes like this (see below). So, subfunctions can lock as much as they want to--gdk_threads_enter/leave is called only once. (a) In your app replace gdk_threads_enter()/leave() functions by calls to your own _enter/_leave functions. (b) have _enter() look like this: - lock_recursive_mutex(...) - check if this is lock level 1, if yes: call gdk_threads_enter() (c) have _leave() look like this: - check if this is lock level 1, if yes: call gdk_threads_leave() - unlock_recursive_mutex(...) (d) leave the *direct* calls to gdk_threads_enter/leave around your gtk_main() or gtk_main_iteration() as is (otherwise you trap into a deadlock on the second call to it) Note: Do not use gdk_threads_set_lock_functions() to facilitate (a) since you may encountere the same problems as me (strange unlocking before locking issues, again gtk freezes etc). (3) DEADLOCKs AT RUNTIME Even if you follow the rules (1) and (2) gtk may freeze in situations like these: You have coded a thread which reads a value from a gtk spinbutton. This works as long as you do not launch the thread by a button click and wait for the threads return. The reason: The button click event locks the gdk lock automatically, and the thread tries to lock also and has to wait--however the button waits for the thread -> deadlock. The general solution which I use is a bunch of work, however it works here in various situations (if there are easier solutions let me know): We need to seperate all events like button clicks (see a below) and data (see b) from gtk. So, the event's code can return immediately and the gdk lock is unlocked again; after that the user's code starts. This implies these two steps: (a) Wrap the needed widgets into your own structures which hold event callback(s) to the user. Here I assume a button widget. On creation pass the user's click event callback. Connect the original gtk's button click event to a static wrapper which calls the user's callback using a thread (to optimize: think thread pools or idle functions). To make life a little easier for the client programmer, connect gtk's widget destroy signal to a function which cleans up the user's widget wrapper struct. All this (a) applies not only to *events* but also to any gtk *actions* like renaming a label etc. for which little delayed execution is o.k. (b) When you need to query gtk widgets (let's say you need a spinbutton's value) however you *cannot* launch a thread since you need the result immediately. So, for these cases, (a) does not apply. To achieve this your widget struct needs to additionally hold the widgets data (e.g. a double for a spinbutton, a string for a labels name) which can be returned *without* entering gtk at all. Keep in mind that when destroying your widget wrapper struct, you may need to free a labels name string as well. Thank's for reading ;-) Felix _______________________________________________ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list