从GUI调用boost :: thread(wxwidgets)并传递回调函数

时间:2014-08-06 15:24:53

标签: callback wxwidgets boost-thread

我有一个带wxwidgets的GUI程序。单击一个Button时,应该启动并运行一个新线程,这样它就不会阻止UI。 从线程中,调用一个函数,该函数将回调函数作为参数。 当我在没有线程的情况下运行程序(因此阻止UI)时,没有问题。 但是当我在下面的代码中使用boost:thread时,线程无法正常运行。 当程序尝试设置成员变量CallBack()时,程序在回调函数m_intValue中停止。这是成功的,没有单独的线程,但当我把它放在一个单独的线程中时挂起。 有什么想法吗?我试图简化代码,使其更具可读性。如果它不能像这样编译,请原谅。我只是问,也许有人知道问题出在哪里!

代码

class MainFrame : public wxFrame
{

 protected:
 boost:thread m_workerThread;
 m_intValue;

 WorkerThread(Foo& afoo, Bar& aBar)
 {
  afoo.doSmth(aBar, boost::bind(&MainFrame::CallBack, this, _1, _2, _3)
 }

 void OnButtonClick()
 {
  Foo oFoo;
  Bar oBar;
  m_workerThread = boost::thread(&MainFrame::WorkerThread, this, boost::ref(oFoo), boost::ref(oBar));
 }

 void CallBack(int arg, int arg1, int arg2 )
 {
  m_intValue = arg;
 }


};

2 个答案:

答案 0 :(得分:1)

显示的代码完全是MT不安全的,因为主线程(也可能是访问m_intValue)和工作线程之间没有同步,在执行回调的上下文中。这可以通过使用临界区或互斥锁来修复,以保护对它的访问。

如果您的真实代码使用回调中的任何wxWidgets UI功能,那么它根本不起作用,如@ravenspoint所述,wxWidgets UI只能在主线程中使用。解决此问题的唯一方法是从主线程执行任何UI代码。

最好的,因为非常简单,这样做的方法是使用CallAfter(),例如。

void WorkerThread()
{
    ...
    wxGetApp().CallAfter(Callback, arg1, arg2);
}

如果你正在使用C ++ 11,一个非常有用的变体是避免定义Callback()而只是做

    wxGetApp().CallAfter([=]() { m_intValue = arg; });

现在这非常安全,因为分配是在主线程中完成的。

答案 1 :(得分:0)

我猜测将WorkerThread和CallBack作为MainFrame的方法是有问题的。 wxWidgets不喜欢在工作线程中运行GUI代码。虽然发布的代码看起来无害,但我想知道你在真正的代码中有什么......?

我建议将WorkerThread和CallBack转换为不从任何wx类继承的新clas - 这将防止您无意中从工作线程执行GUI代码并造成破坏。