Hey,

Was this posted online? I checked:
http://library.gnome.org/devel/gtkmm-tutorial/2.99/index.html.en
<http://library.gnome.org/devel/gtkmm-tutorial/2.99/index.html.en>but
couldn't find it there...

Cheers, -Harry

PS: Thanks Chris for taking time to write about threading / sigc / gtkmm,
I've been
struggling to find documentation, and experience is the way to learn how
to thread badly and with lots of segfaults..!

On Wed, Mar 16, 2011 at 10:41 PM, Chris Vine <[email protected]>wrote:

> Hi,
>
> In order to deal in part with the issues thrown up by the bug report at
> https://bugzilla.gnome.org/show_bug.cgi?id=512348 , I have agreed to
> contribute a new section to the gtkmm tutorial on writing
> multi-threaded programs using gtkmm.  This will reduce the risk of too
> many people writing thread unsafe code because of the (partly hidden)
> problems associated with libsigc++.
>
> The text set out below (which for ease of reading is at this stage in
> plain text rather than formatted XML) is drawn from my own experience in
> writing multi-threaded code and in going through the tedious business of
> inspecting libsigc++ in order to determine what is safe and what is
> not. However, I know I am not the only person to have been faced with
> this so if anyone else has any gotchas which they have come across and
> which I have not mentioned, or suggestions arising from their own
> experience, I would like to hear about them.
>
> Regards,
>
> Chris
>
>
> ***********************
>
> Writing multi-threaded programs using gtkmm
>
> The constraints
>
> Programs employing multiple threads of execution can be written using
> gtkmm, as glibmm wraps the functions and objects provided by glib for
> threads, and so provides the normal set of thread launching functions,
> mutexes, condition variables and scoped locking classes required for
> writing multi-threaded programs using C++. Those using recent versions
> of g++'s C++0x implementation can also make use of the thread
> facilities to be provided by the forthcoming C++11/12 standard, in
> combination with glibmm and gtkmm.
>
> However, care is required arising from the fact that libsigc++ is not
> thread-safe.  Amongst other things, a class inheriting from
> sigc::trackable will, via that inheritance, have a std::list object
> keeping track of slots connected to any of its non-static methods.
> Each sigc::slot object also keeps, via sigc::slot_rep, its own
> sigc::trackable object to track any sigc::connection objects which it
> needs to inform about its demise.  sigc::signal objects also keep
> lists of slots, which will be updated with a call to its connect()
> method or calls to any sigc::connection object relating to such a
> connection.  None of these are protected by mutexes or other means of
> synchronization.
>
> This requires a number of rules to be observed when writing
> multi-threaded programs using gtkmm:
>
> 1.  Although code written for the X11 backend of GTK+ can use the GDK
> global lock, as invoked by gdk_threads_enter() and
> gdk_threads_leave(), so as to address GTK+ in more than one thread,
> because of libsigc++ this will not usually work with gtkmm.  Instead,
> if a worker thread needs to invoke a gtkmm function, it should do so
> via Glib::Dispatcher.  Glib::Dispatcher is the key to writing
> successful multi-threaded code using glibmm and gtkmm, and is dealt
> with in more detail below.  (As it happens, this approach also provides
> a cleaner program structure than using the global lock.)
>
> 2.  Unless special additional synchronization is employed, any
> particular sigc::signal object should be regarded as 'owned' by the
> thread which created it.  Only that thread should connect slots with
> respect to the signal object, and only that thread should emit() or
> call operator()() on it.
>
> 3.  Unless special additional synchronization is employed, any
> sigc::connection object should be regarded as 'owned' by the thread
> which created the slot and called the method which provided the
> sigc::connection object.  Only that thread should call
> sigc::connection methods on the object.
>
> 4.  A slot which references a non-static method of a class deriving
> from sigc::trackable should never be copied to another thread (one
> consequence of this is that Glib::Thread::create() should not be
> called with a slot argument which represents a non-static method of
> such a class).
>
> 5.  If a particular class object derives from sigc::trackable, only
> one thread should create slots representing any of its non-static
> methods (that is, create slots with sigc::mem_fun()).  The first
> thread to create such a slot should be regarded as owning the relevant
> object for the purpose of creating further slots referencing ANY of
> its non-static methods.
>
> 6.  Although glib is itself thread-safe (assuming Glib::thread_init()
> has been called), any glibmm wrappers which use libsigc++ will not be.
> So for example, the only thread which should call
> Glib::SignalIdle::connect(), Glib::SignalIdle::connect_once(),
> Glib::SignalIO::connect(), Glib::SignalTimeout::connect(),
> Glib::SignalTimeout::connect_once(),
> Glib::SignalTimeout::connect_seconds,
> Glib::SignalTimeout::connect_seconds_once(), and manipulate any
> sigc::connection object returned by them, is the thread in which the
> main loop to which the connection is made runs.  (The connect*_once()
> variants could be made thread-safe for any case where the slot does
> not relate to a non-static method of a class deriving from
> sigc::trackable, but that has not yet been implemented.)
>
> Point 5 above is particularly unintuitive.  The overall message is:
> take extra care when deriving classes from sigc::trackable in
> multi-threaded programs.
>
> Using Glib::Dispatcher
>
> The slots connected to sigc::signal objects execute in the thread
> which calls emit() or operator()() on the signal.  Glib::Dispatcher
> does not behave this way: instead its connected slots execute in the
> thread in which the Glib::Dispatcher object was constructed (which
> must have a glib main loop).  If a Glib::Dispatcher object is
> constructed in the main GUI thread (which will therefore be the
> receiver thread), any worker thread can emit on it and have the
> connected slots safely execute gtkmm functions.
>
> Some thread-safety rules on the use of Glib::Dispatcher still apply:
> only the receiver thread (normally the main GUI thread) should call
> connect() on it, or manipulate any related sigc::connection object,
> unless additional synchronization is employed.  However, any worker
> thread can safely emit on it without any locking once the receiver
> thread has connected the slots, provided that the Glib::Dispatcher
> object is constructed before the worker thread is started (if it is
> constructed after the thread has started, additional synchronization
> will normally be required to ensure visibility).
>
> Aside from the fact that connected slots always execute in the receiver
> thread, Glib::Dispatcher objects are similar to sigc::signal<void>
> objects.  They therefore cannot pass unbound arguments nor return a
> value.  The best way to pass unbound arguments is with a thread-safe
> (asynchronous) queue.  At the time of writing glibmm does not have one,
> although most people writing multi-threaded code will have one
> available to them (they are relatively easy to write although there are
> subtleties in combining thread-safety with strong exception safety).
>
> A Glib::Dispatcher object can be emitted on by the receiving thread as
> well as by a worker thread, although this should be done within
> reasonable bounds.  Glib::Dispatcher objects share a single common
> pipe, which could in theory at least fill up on a very heavily loaded
> system running a program with a very large number of Dispatcher
> objects in use.  Were the pipe to fill up before the receiving
> thread's main loop has had an opportunity to read from it to empty it,
> and the receiving thread attempt to emit and so write to it when it is
> in that condition, the receiving thread would block on the write, so
> deadlocking.  Where the receiving thread is to emit, a normal
> sigc::signal<void> object can of course be used instead.
>
>
>
> _______________________________________________
> gtkmm-list mailing list
> [email protected]
> http://mail.gnome.org/mailman/listinfo/gtkmm-list
>
_______________________________________________
gtkmm-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtkmm-list

Reply via email to