我有一个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会有问题吗?这样做是否安全,只要我确定变量只是由一个线程修改或者是否有更好的方法?
答案 0 :(得分:2)
你有竞争条件。即使你的gui线程没有修改thread_message
,允许GUI线程在另一个线程修改它时读取它也不会给你带来长期的快乐。这是因为std :: string本身不受多个访问它的线程的保护,并且有多个内部字段。如果一个线程正在修改其内部字段之一,而另一个线程正在读取它们,则从第二个角度来看内部状态将不一致。
您可以在GUI类中使用互斥锁来保护对另一个线程可能访问的变量的访问。在get / set例程中锁定和解锁互斥锁,并将这些例程用于所有其他访问,以确保一次只有一个线程可以访问或修改变量。
答案 1 :(得分:0)
通常,互斥量的使用不足以实现所需的行为。相同的工作线程(如果你有另一个工作线程)可能想要发送另一条消息,而第一条线程尚未被主线程处理。这就是为什么除了互斥锁之外你应该使用消息队列(例如std::deque<std::string>
类的对象)而不仅仅是std::string Some_GUI_class::thread_message
变量来避免这种消息丢失。