约束条件

由于libsigc++(尤其是sigc::trackable)不是线程安全的,所以在编写基于gtkmm的多线程程序时需要格外小心。这是因为使用libsigc++时在幕后发生的复杂交互不受互斥量或其他同步方式的保护。

27.1.1. 规则

在使用gtkmm编写多线程程序时需要遵守许多规则。这些规则下下面列出,但要注意的一点是从sigc::trackable派生类时需要格外小心,因为效果很不直观(特别是下述4、5条)。

  1. 使用Glib::Dispatcher在工作线程中调用gtkmm函数(这点将在下一节详细介绍)

  2. sigc::signal对象被创建其的线程所拥有。只有该线程应该将sigc::slot对象连接到信号对象,并且只有该线程应该在emit()信号或在信号上调用operator()()或是将已连接的sigc::slot对象置空。因此任何由gtkmm部件提供的信号对象都只应该在主GUI线程进行操作,以及任何从sigc::trackable派生的对象(其非静态方法由连接到信号对象的槽引用)都应该在该线程中销毁。

  3. 任何sigc::connection对象都应视线程的拥有者在此线程调用了返回sigc::connection对象的方法。只有该线程才应在此对象上调用sigc::connection方法。

  4. 通过调用sigc::mem_fun()函数创建的sigc::slot对象具有由sigc::trackable所派生类的成员函数的引用,请勿将其复制到另一个线程中,也不要让除创建线程以外的线程销毁它。

  5. 如果从sigc::trackable派生一个特定的类对象,只应有一个线程通过调用sigc::mem_fun()创建代表该类任意非静态成员函数的sigc::slot对象。第一个创建这样的槽的线程被视为拥有相关对象的线程。这个线程可以对该类的任意非静态成员函数使用该函数以创建槽,或者在sigc::trackable对象断开连接和被销毁时将那些槽无效化。

  6. 尽管glib自身是线程安全的,但是任何使用了libsigc++glibmm封装都不会是线程安全的。因此只有在运行主循环的线程的主循环中才能调用Glib::SignalIdle::connect()Glib::SignalIO::connect()Glib::SignalTimeout::connect()Glib::SignalTimeout::connect_seconds或是处理由它们返回的sigc::connection对象。

    对于Glib::SignalIdle::connect_once()Glib::SignalTimeout::connect_once()Glib::SignalTimeout::connect_seconds_once()等connect*_once()变体函数而言,只要它们使用的槽不是通过对sigc::trackable派生类的成员函数调用sigc::mem_fun()创建的,那么它们在任何情况下都是线程安全的。