2012-04-26 54 views
2

我有一个gtkmm应用程序,我试图把一些长时间运行的任务放到不同的线程中,这样他们就不会锁定GUI。这里有一个教程,我根据我的设计:C++ Gtk线程。我做对了吗?

http://www.velvetcache.org/2008/09/30/gtkmmglibmm-thread-example

我用油嘴::调度信号通知GUI线程,当工作完成或需要更新的东西,但我不知道如何在工作线程和GUI线程之间传递数据。到目前为止,我一直在传递一个指向创建worker的类的指针,然后修改这个类的public成员,但是有些东西告诉我这不是最正确的做法。这里有一个例子:

class Some_GUI_class 
{ 
public: 
    std::string thread_message; 

private: 
    Worker_class* worker; 

    void start_worker() 
    { 
     if (worker != NULL) return; 

     worker = new Worker_class(this); 
     worker->sig_message.connect(sigc::mem_fun(*this, &Some_GUI_class::display_message_from_thread); 
     worker.start(); 
    }   

    void display_message_from_thread() 
    { 
     some_label->set_text(thread_message); 
    } 
} 

class Worker_class 
{ 
public: 
    Worker_class(Some_GUI_class* gui_class) : gui_class(gui_class) 
    {} 

    void start() 
    { 
     thread = Glib::Thread::create(sigc::mem_fun(*this, &Worker_class::run), true); 
    } 

    Glib::Dispather sig_message; 

protected: 
    Glib::Thread* thread; 
    Glib::Mutex mutex; 

    Some_GUI_class* gui_class; 

    void run() 
    { 
     // ... 
     gui_class->thread_message = "Message from a thread!"; 
     sig_message();     
    } 

} 

这essentialy的作品,但我想如果GUI线程要同时修改thread_message会有问题吗?这样做是否安全?只要我确定变量只能由单个线程修改或者有更好的方法?

+0

我不是gtk专家,但据我记得你有一个UI的消息循环,所以你需要在主线程中捕获这些消息,然后触发事件,它的棘手。 – 2012-04-26 15:14:29

+0

@JakubOboza这是Glib :: Dispatcher所做的。 – ergosys 2012-04-26 21:46:14

回答

2

你有一个竞赛条件。即使你的gui线程不修改thread_message,允许GUI线程读取它,而另一个线程正在修改它不会给你长期的快乐。这是因为std :: string本身不受多线程访问的保护,并且有多个内部字段。如果一个线程正在修改其内部字段之一,而另一个线程正在读取它们,则从第二个线程的角度来看,内部状态将不一致。

您可以在GUI类中使用互斥锁来保护对另一个线程可能访问的变量的访问。在get/set例程中锁定和解锁互斥锁,并将这些例程用于所有其他访问,以确保一次只有一个线程访问或修改变量。

+0

谢谢。这就说得通了。你能否提供一个关于如何实现它的简单代码示例。我只需添加互斥体类成员并调用Glib :: Mutex :: Lock lock(mutex);在get/set方法的顶部? – jaho 2012-04-27 09:17:56

+1

基本上就是这样。要明确一点,既然你在保护数据成员,你的互斥量应该是数据成员(而不是类(静态)成员)。 – ergosys 2012-04-27 18:13:15

0

一般来说,互斥量的使用不足以实现所需的行为。同一个工作线程(或另一个工作线程,如果有的话)可能想要发送另一个消息,而第一个线程还没有被主线程处理。这就是为什么除了互斥之外,您还应该使用消息队列(例如std::deque<std::string>类的对象)而不是仅使用std::string Some_GUI_class::thread_message变量来避免这种类型的消息丢失。