Re: Proper way to provide gtk+ app with asynchronous data?



NavEcos wrote:

I'm also curious why gtk_threads_init() doesn't just do the
gdk_threads_enter() and gdk_threads_leave() for ALL GTK functions?  GTK
knows the PID of the process that called gnome_init() - if the PID is
different than the primary threads, why not just handle gdk_threads_enter()
and .._leave() for you by all the gtk functions?  I know this is a major
overhaul, but it doesn't seem like it would incurr much of a penalty in
performance, especially considering how much error checking is done already
on casting variables.


This can absolutely not be done and the reasons should be rather obvious.

First of all, if you make a series of GTK+ calls you should put all those calls within a single enter/leave block.

There are two reasons for that, the first beeing performance. Each gdk_threads_enter() blocks on the GTK+ lock until it becomes available, and each leave() gives away the lock to another contender if there is one. So calling enter()/leave() around each GTK+ call would make the application flip-flop among threads between each and every GTK+ call, which would be very inefficient.

This brings us into the second reason, which is consistency. What if you want to get the value from a GtkEntry, modify it, and the put it back into the GtkEntry, for example? If you don't put that code inside a single enter/leave block, some other thread (possibly even the user) can mess around with the GtkEntry while you're modifying it, which would intermittently cause very strange application behaviour or even crashes.

Secondly, any pointer to shared data, whether it is a GTK+ structure or application data, must NOT be dereferenced unless the thread dereferencing it is holding a lock on that data. This rule applies for both reading and writing the data. For application data you could always implement your own locks, but for GTK+ data you have to use enter()/leave().

As with the GtkEntry example, the locking scope is just as important for consistency here. Typically, you would do all operations on a shared data structure within a single locking scope, in which also the pointer is obtained, but this is different from case to case. There is no simple catch-all algorithms that will guarantee consistency automatically for you.

If these rules are not carefully obeyed, all sorts of strange things can happen. Your application may seem to work fine, but once in a while it would misbehave or crash. Or it may work just fine on a single-processor box, but fail miserably on a multiprocessor machine.

Bottom line is that the programmer need to understand exactly the issues involved with sharing data between threads, or he/she should better stay away from using them in the first place.

--
Christer Palm



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]