【问题标题】:C++ Gtk threading. Am I doing it right?C++ Gtk 线程。我做对了吗?
【发布时间】:2012-04-26 15:06:41
【问题描述】:

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

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

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

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_message 会有问题吗?只要我确定变量仅由单个线程修改还是有更好的方法,这样做是否安全?

【问题讨论】:

  • 我不是 gtk 专家,但据我所知,您有一个 UI 消息循环,因此您需要在主线程中捕获此消息并将其作为事件触发,这很棘手。
  • @JakubOboza 这就是 Glib::Dispatcher 所做的。

标签: c++ multithreading glib gtkmm


【解决方案1】:

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

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

【讨论】:

  • 谢谢。这就说得通了。您能否提供一个关于如何实现它的简单代码示例。我只是添加互斥锁类成员并调用 Glib::Mutex::Lock lock (mutex);在 get/set 方法的顶部?
  • 基本上就是这样。为了清楚起见,由于您正在保护数据成员,因此您的互斥锁应该是数据成员(而不是类(静态)成员)。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    相关资源
    最近更新 更多