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
