【问题标题】:Is it bad to create a global wxCriticalSection variable in wxWidgets?在 wxWidgets 中创建一个全局 wxCriticalSection 变量是不是很糟糕?
【发布时间】:2018-01-14 13:03:55
【问题描述】:

我正在使用wxTreeListCtrl 来显示一棵树。对于树节点的每次扩展,我都会创建一个调用后端 API 并返回响应的线程。执行完每个线程后,会执行一个HandleExpansionRequest(),它将响应元素添加到树中。这些操作运行良好。

问题是: 情况1:当线程正在执行后端函数时,同时如果用户关闭主框架,则在Entry()中执行wxQueueEvent会出现异常。 要解决这个问题: 我没有在窗口关闭时删除线程,而是使用变量isFrameClosed 并在线程为主代码创建wxQueueEvent 之前检查它。我的疑问是,这是在框架关闭但线程仍在执行后停止程序崩溃的好方法(因为我正在创建全局 wxCriticalSection )?

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_TREELIST_ITEM_EXPANDED(wxID_ANY, MyFrame::OnItemExpand)   
EVT_THREAD(ITEM_BROWSE_WORKER_EVENT,MyFrame::OnExpandThreadCompletion)
END_EVENT_TABLE()

//using below 2 variables to avoid crash when item expansion request is sent and user closes the frame.
 wxCriticalSection cs_forisFrameClosed;
 static bool isFrameClosed;

MyFrame::MyFrame()
{
   {
    wxCriticalSectionLocker lock(cs_forisFrameClosed);
    isFrameClosed = false;
   }
   //remaining code ...
}

MyFrame::~MyFrame()
{
   {
    wxCriticalSectionLocker lock(cs_forisFrameClosed);
    isFrameClosed = true;
   }
}

void MyFrame::OnItemExpand(wxTreeListEvent& event)
{
     MyThread *thread = new MyThread(this);
    if (thread->Create() != wxTHREAD_NO_ERROR)
    {
        PrintError(__FUNCTION__, "Can't create thread!");
    }
    thread->Run();
}

MyThread::MyThread(MyFrame *frame) : wxThread()
{
    m_frame = frame;
}

wxThread::ExitCode MyThread::Entry()
{
    string resp;
    GetResponseFromBackEnd(resp);
    {
        wxCriticalSectionLocker lock(cs_forisFrameClosed);
        if (!isFrameClosed)
        {
            wxThreadEvent event(wxEVT_THREAD, ITEM_BROWSE_WORKER_EVENT);
            event.SetString(resp);
            wxQueueEvent(m_frame, event.Clone());
        }
    }
}


void MyFrame::OnExpandThreadCompletion(wxThreadEvent &event)
{
    // this function is executed after every thread returns.
    // take response from event and update tree with children.      
}

【问题讨论】:

    标签: c++ multithreading wxwidgets


    【解决方案1】:

    正如the docs 所说,分离的线程会自行删除,因此您不能删除它们,因为这会导致执行两次。相反,您必须实现某种与线程通信的方式,并要求它在该执行此操作时退出。 wxMessageQueue 提供了一种最简单的方法。

    【讨论】:

    • 另外thread sample给出了一个例子,在app类中使用bool变量和信号量来保证关闭frame时线程被删除。
    • 我已经编辑了我的问题,创建了一个全局WxCriticalSectionisFrameClosed。我在构造函数中创建isFrameClosed = false,在析构函数中创建true。 & 在执行 wxQueueEvent 之前检查每个线程 entry() 中的 isFrameClosed。它解决了我的问题。但是将这个 wxCriticalSection 声明为全局参数是否是一种好方法?
    • @VZ 请检查已编辑的问题。我找到了一个解决方案,但我不确定这是否是一种好的编码习惯。
    • 这确实应该是一个新问题,和原来的问题无关。简而言之:这是不安全的,如果在帧被销毁之前发送事件,您的代码可能会崩溃。
    【解决方案2】:

    尝试在你的 close 方法中加入()所有产生的线程。

    【讨论】:

    • 我不能使用 join,因为主程序窗口冻结,因为后端 api 需要更多时间来响应。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 2013-05-08
    • 1970-01-01
    • 2011-09-20
    • 2018-01-20
    相关资源
    最近更新 更多