Re: Adding custom GDK events



On Sunday 14 January 2007 00:38, Chris Vine wrote:
[snip]
> As I think you are saying, this does not in itself ensure memory visibility
> of the callback function pointer or data argument of the idle callback (or
> any other data passed between the threads concerned) and if visibility on
> multi-processor systems is required then some form of memory
> synchronisation (fences or barriers) will be required, typically by means
> of mutex locking of the data.
>
> In practice however I suspect this will be achieved since I am pretty sure
> (although this perhaps should be checked and I will do so next week ...
[snip]

Having now looked at glib/gmain.c it seems to me that g_idle_add() is thread 
safe (in the wider sense that it can be used to pass messages to/execute 
callbacks in the main loop thread from other threads, as well as in the 
narrow sense that the main loop is thread safe).  The same appears to apply 
to Glib::SignalIdle.

Each GMainContext object has a mutex associated with it which is used to lock 
main context operations.  g_idle_add_full() creates the new idle source 
object and then calls g_source_set_callback(), which assigns (amongst other 
things) the function pointer and data arguments to the data members of the 
relevant idle source object.  At this point the memory representing the 
function pointer and data argument is unsynchronised.  However it follows 
this with a call to g_source_attach() which attaches the idle source object 
to the relevant GMainContext object under the mutex lock for that main 
context (an acquire and a release).

When the data members of the idle source object are read for dispatching, 
g_main_context_dispatch(), which calls g_main_dispatch(), does so under the 
same mutex lock, with an acquire and a release.  Therefore, when the main 
loop thread reads these data members, there has been (a) a release operation 
by the signalling thread, and (b) an acquire operation on the same 
synchronisation object by the reading thread.  Accordingly the memory of the 
reading thread will be synchronised with that of the signalling thread to a 
condition no earlier than the release instruction being executed, and no out 
of order execution of the write will be permitted beyond the point of the 
acquire or the point of synchronisation, assuming a platform with these 
minimum-level thread safety guarantees.  (Actually Posix, in section 4.10, 
General Concepts, Memory Synchronization, gives stronger guarantees than 
that.)

You know glibmm better than me, but it seems to me that the same would apply 
to that.  Glib::signal_idle().connect() will create the idle source, and then 
call Glib::SignalIdle::connect() on it, which will invoke g_source_attach().  
The only thing I notice is that Glib::SignalIdle::connect(), after the call 
to g_source_attach(), calls Glib::SourceConnectionNode::install().  I do not 
know what that does, but if it is important to dispatch of the slot in the 
main loop by the relevant GMainContext object you could always put 
LOCK_CONTEXT(context_)/UNLOCK_CONTEXT(context_) around it (or if it makes 
sense to put the call to Glib::SourceConnectionNode::install() before the 
call to g_source_attach(), put it before the call to g_source_attach()).

As it happens, I recall the PyGTK FAQ recommending using gobject.idle_add() as 
the way to pass events to the main thread (although their FAQ page does not 
seem to be responding at the moment).

Chris




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