Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;Gtk螺纹。我做得对吗?_C++_Multithreading_Glib_Gtkmm - Fatal编程技术网

C++ C++;Gtk螺纹。我做得对吗?

C++ C++;Gtk螺纹。我做得对吗?,c++,multithreading,glib,gtkmm,C++,Multithreading,Glib,Gtkmm,我有一个gtkmm应用程序,我试图将一些长时间运行的任务放在单独的线程中,这样它们就不会锁定GUI。以下是我的设计基于的教程: 我使用Glib::Dispatcher信号在工作完成或需要更新某些内容时通知GUI线程,但是我不确定如何在工作线程和GUI线程之间传递数据。到目前为止,我一直在向创建worker的类传递一个指针,然后修改该类的公共成员,但有些事情告诉我这样做不是最正确的。下面是一个例子: class Some_GUI_class { public: std::string t

我有一个gtkmm应用程序,我试图将一些长时间运行的任务放在单独的线程中,这样它们就不会锁定GUI。以下是我的设计基于的教程:

我使用Glib::Dispatcher信号在工作完成或需要更新某些内容时通知GUI线程,但是我不确定如何在工作线程和GUI线程之间传递数据。到目前为止,我一直在向创建worker的类传递一个指针,然后修改该类的公共成员,但有些事情告诉我这样做不是最正确的。下面是一个例子:

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();                
    }

}

这在本质上是可行的,但是我想如果GUI线程想要同时修改thread_消息,那么会有问题吗?这样做安全吗?只要我确定变量仅由单个线程修改,还是有更好的方法?

您有一个竞争条件。即使您的gui线程没有修改
thread\u消息
,允许gui线程在另一个线程修改它时读取它也不会给您带来长期的快乐。这是因为std::string本身不受多线程访问的保护,并且具有多个内部字段。如果一个线程正在修改其一个内部字段,而另一个线程正在读取这些字段,那么从第二个线程的角度来看,内部状态将不一致


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

通常,互斥体的使用不足以实现所需的行为。当主线程尚未处理第一条消息时,同一个工作线程(如果有的话,也可以是另一条)可能想要发送另一条消息。这就是为什么除了互斥外,还应该使用消息队列(例如
std::dequestd::string
class的对象)不要只使用
std::string一些\u GUI\u class::thread\u message
变量来避免这种消息丢失。

我不是gtk专家,但据我所知,UI有一个消息循环,所以您需要在主线程中捕获这些消息,然后作为事件触发,这很棘手。@jakubobza Glib::Dispatcher就是这么做的。谢谢。这是有道理的。您能否提供一个简单的代码示例来说明如何实现它。我是否只需要添加互斥体类成员并调用Glib::mutex::Lock(互斥体);在get/set方法的顶部?基本上就是这样。需要明确的是,由于您是在保护数据成员,所以互斥对象应该是数据成员(而不是类(静态)成员)。