Chapter 29. Multi-threaded programs

# Chapter 29. Multi-threaded programs

## The constraints

Care is required when writing programs based on gtkmm using multiple threads of execution, arising from the fact that libsigc++, and in particular `sigc::trackable`, are not thread-safe. That's because none of the complex interactions that occur behind the scenes when using libsigc++ are protected by a mutex or other means of synchronization. [1]

### The rules

This requires a number of rules to be observed when writing multi-threaded programs using gtkmm. These are set out below, but one point to note is that extra care is required when deriving classes from `sigc::trackable`, because the effects are unintuitive (see particularly points 4 and 5 below).

1. Use `Glib::Dispatcher` to invoke gtkmm functions from worker threads (this is dealt with in more detail in the next section).

2. A `sigc::signal` object should be regarded as owned by the thread which created it. Only that thread should connect a `sigc::slot` object to the signal object, and only that thread should `emit()` or call `operator()()` on the signal, or null any connected `sigc::slot` object. It follows (amongst other things) that any signal object provided by a gtkmm widget should only be operated on in the main GUI thread and any object deriving from `sigc::trackable` having its non-static methods referenced by slots connected to the signal object should only be destroyed in that thread.

3. Any `sigc::connection` object should be regarded as owned by the thread in which the method returning the `sigc::connection` object was called. Only that thread should call `sigc::connection` methods on the object.

4. A `sigc::slot` object created by a call to `sigc::mem_fun()` which references a method of a class deriving from `sigc::trackable` should never be copied to another thread, nor destroyed by a different thread than the one which created it.

5. If a particular class object derives from `sigc::trackable`, only one thread should create `sigc::slot` objects representing any of the class's non-static methods by calling `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 using that function, or nulling those slots by disconnecting them or destroying the trackable object.

6. Although glib is itself thread-safe, any glibmm wrappers which use libsigc++ will not be. So for example, only the thread in which a main loop runs should call `Glib::SignalIdle::connect()`, `Glib::SignalIO::connect()`, `Glib::SignalTimeout::connect()`, `Glib::SignalTimeout::connect_seconds` for that main loop, or manipulate any `sigc::connection` object returned by them.

   The connect*_once() variants, `Glib::SignalIdle::connect_once()`, `Glib::SignalTimeout::connect_once()`, `Glib::SignalTimeout::connect_seconds_once()`, are thread-safe for any case where the slot is not created by a call to `sigc::mem_fun()` which represents a method of a class deriving from `sigc::trackable`.

[1] These interactions arise from the fact that, amongst other things, a class inheriting from `sigc::trackable` will, via that inheritance, have a `std::list` object keeping track of slots created by calls to `sigc::mem_fun()` representing any of its non-static methods (more particularly it keeps a list of callbacks which will null the connected slots on its destruction). 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, and also has a function to deregister itself from any `sigc::trackable` on disconnection or destruction. `sigc::signal` objects also keep lists of slots, which will be updated by a call to their `connect()` method or calls to any `sigc::connection` object relating to such a connection.

Custom Widgets |  | Using Glib::Dispatcher