我有一个带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;
}
};
答案 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代码并造成破坏。