【问题标题】:Invoking a boost::thread from the GUI (wxwidgets) and pass a callback function从 GUI (wxwidgets) 调用 boost::thread 并传递回调函数
【发布时间】:2014-08-06 15:24:53
【问题描述】:

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

代码

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


};

【问题讨论】:

    标签: callback wxwidgets boost-thread


    【解决方案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; });
    

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-01
        相关资源
        最近更新 更多