Las limitaciones

glibmm proporciona el conjunto normal de funciones de lanzamiento de hilos, exclusión mutua, variables condicionales y clases de bloqueo de alcance requeridas para escribir programas de múltiples hilos usando C++.

Sin embargo, hay que tener cuidado cuando se escriben programas basados en gtkmm usando múltiples hilos de ejecución, dado que libsigc++, y en particular sigc::trackable, no son seguras con hilos. Eso es porque ninguna de las complejas interacciones que ocurran internamente cuando usa libsigc++ están protegidas por una exclusión mutua u otros métodos de sincronización. 1

29.1.1. Las reglas

Esto requiere que se observen una cantidad de reglas cuando escribe programas de múltiples hilos usando gtkmm. Estas se exponen abajo, pero un punto a destacar es que se requiere cuidado adicional cuando deriva clases de sigc::trackable, porque los efectos no son intuitivos (consulte particularmente los puntos 4 y 5 debajo).

  1. Use Glib::Dispatcher para invocar las funciones de gtkmm desde hilos de trabajo (esto se explica con má detalle en la próxima sección).

  2. Un objeto sigc::signal debe considerarse propiedad del hilo que lo creó. Solo ese hilo debe conectar un objeto sigc::slot al objeto de la señal, y solo ese hilo debe llamar a emit() u operator()() sobre la señal, o anular cualquier objeto sigc::slot conectado. Sigue (junto a otras cosas) que cualquier objeto de señal proporcionado por un widget de gtkmm solo se opere en el hilo principal de la IGU y cualquier objeto que derive de sigc::trackable con métodos no estáticos referenciados por «slots» conectados al objeto de señal solo deben destruirse en ese hilo.

  3. Cualquier objeto sigc::connection solo debe considerarse propiedad del hilo en el que se llamó al método que devuelve el objeto sigc::connection. Solo ese hilo debe llamar a métodos de sigc::connection sobre el objeto.

  4. Un objeto sigc::slot creado por una llamada a sigc::mem_fun() que referencia un método de una clase que deriva de sigc::trackable nunca debe copiarse a otro hilo, ni otro hilo aparte del que lo creó lo debe destruir. (Una consecuencia de esto es que Glib::Threads::Thread::create() no debe llamarse con un argumento de «slot» creado por una llamada a sigc::mem_fun() que represente a un método de una clase semejante. Sin embargo, es seguro pasarle Glib::Threads::Thread::create() a un objeto de función representando un método así usando, por ejemplo, boost::bind() o, en C++11, std::bin() o una expresión lambda de C++11).

  5. Si un objeto de clase particular deriva de sigc::trackable, solo un hilo debe crear objetos sigc::slot representando cualquiera de los métodos no estáticos de la clase llamando a sigc::mem_fun(). El primer hilo que cree un «slot» semejante debe considerarse dueño del objeto relevante con el propósito de crear más «slots» referenciando a cualquiera de sus métodos no estáticos que usan esa función, o anulando aquellos «slots» desconectándolos o destruyendo el objeto «trackable».

  6. A pesar de que glib en sí es segura para hilos, cualquier envoltorio de glibmm que use libsigc++ no lo será. Entonces por ejemplo solo el hilo en el bucle principal debe llamar a Glib::SignalIdle::connect(), Glib::SignalIO::connect(), Glib::SignalTimeout::connect(), Glib::SignalTimeout::connect_seconds para ese bucle principal, o manipular cualquier objeto sigc::connection que devuelvan.

    Las variantes de «connect*_once()», Glib::SignalIdle::connect_once(), Glib::SignalTimeout::connect_once(), Glib::SignalTimeout::connect_seconds_once(), son seguras para hilos para cualquier caso en el que el «slot» no lo cree una llamada a sigc::mem_fun() que represente a un método de una clase derivada de sigc::trackable. Esto es similar a Glib::Threads::Thread::create() como se menciona en el punto 4.

1

Estas interacciones nacen del hecho de que, entre otras cosas, una clase que hereda de sigc::trackable tendrá, por herencia, un objeto std::list que rastrea los «slots» creados por llamadas a sigc::mem_fun() y representa cualquiera de sus métodos no estáticos (en mayor detalle, mantiene una lista de retornos de llamada que anularán los «slots» conectados en su destrucción). Cada objeto sigc::slot también mantiene, a través de sigc::slot_rep, su propio objeto sigc::trackable para rastrear cualquier objeto sigc::connection al que necesite informarle su caída, y también tiene una función para deregistrarse de cualquier sigc::trackable en desconexión o destrucción. Los objetos sigc::signal también mantienen listas de «slots», que se actualizan mediante llamadas a su método connect() o llamadas a cualquier objeto sigc::connection relacionado a dicha conexión.