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. As mentioned, a
Glib::Dispatcher
object must be constructed in
the receiver thread (the thread in whose main loop it will execute its
connected slots). By default this is the main program thread, although
there is a Glib::Dispatcher
constructor which
can take the Glib::MainContext
object of any
thread which has a main loop. Only the receiver thread should call
connect()
on the
Glib::Dispatcher
object, or manipulate any
related sigc::connection
object, unless
additional synchronization is employed. However, any worker thread can
safely emit on the Glib::Dispatcher
object
without any locking once the receiver thread has connected the slots,
provided that it 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 receiver thread as well as by a worker thread, although this
should be done within reasonable bounds. On unix-like systems
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 receiver thread's main loop has had an opportunity
to read from it to empty it, and the receiver thread attempt to emit
and so write to it when it is in that condition, the receiver thread
would block on the write, so deadlocking. Where the receiver thread is
to emit, a normal sigc::signal<void>
object could of course be used instead.