2010-06-01 22 views
4

我正在使用wxWidgets,並調用需要很長時間才能繼續執行的功能。我想在後臺執行此操作。wxWidgets中的線程

我該怎麼做?

感謝您的幫助

+0

這可能有助於 http://docs.wxwidgets.org/trunk/classwx_thread_helper.html – Aif 2010-06-01 20:32:55

+0

這... http://wiki.wxwidgets.org/Inter-Thread_and_Inter-Process_communication – laher 2010-06-01 21:19:18

回答

2

如果你只需要有一些工作在後臺,直到它完成 - 火,如果你會忘記,這樣的事情:

// warning: off the top of my head ;-) 
class MyThread 
    : public wxThread 
{ 
public: 
    MyThread() : wxThread(wxTHREAD_DETACHED) 
    { 
    if(wxTHREAD_NO_ERROR == Create()) { 
     Run(); 
    } 
    } 
protected: 
    virtual ExitCode Entry() 
    { 
    // do something here that takes a long time 
    // it's a good idea to periodically check TestDestroy() 
    while(!TestDestroy() && MoreWorkToDo()) { 
     DoSaidWork(); 
    } 
    return static_cast<ExitCode>(NULL); 
    } 
}; 

MyThread* thd = new MyThread(); // auto runs & deletes itself when finished 
6

我使用過在wxWidgets中以幾乎所有的方式描述here,我可以說使用自定義事件雖然最初有點複雜,但從長遠來看可以節省一些頭痛的問題。 (該wxMessageQueue類是相當不錯的,但是當我使用它,我發現它泄漏;我沒有在一年內檢查它雖然。)

一個基本的例子:

MyFrm.cpp

#include "MyThread.h" 

BEGIN_EVENT_TABLE(MyFrm,wxFrame) 
    EVT_COMMAND(wxID_ANY, wxEVT_MYTHREAD, MyFrm::OnMyThread) 
END_EVENT_TABLE() 
void MyFrm::PerformCalculation(int someParameter){ 
    //create the thread 
    MyThread *thread = new Mythread(this, someParameter); 
    thread->Create(); 
    thread->Run(); 
    //Don't worry about deleting the thread, there are two types of wxThreads 
    //and this kind deletes itself when it's finished. 
} 
void MyFrm::OnMyThread(wxCommandEvent& event) 
{ 
    unsigned char* temp = (unsigned char*)event.GetClientData(); 
    //do something with temp, which holds unsigned char* data from the thread 
    //GetClientData() can return any kind of data you want, but you have to cast it. 
    delete[] temp; 
}  

MyThread.h

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <wx/thread.h> 
#include <wx/event.h> 

BEGIN_DECLARE_EVENT_TYPES() 
    DECLARE_EVENT_TYPE(wxEVT_MYTHREAD, -1) 
END_DECLARE_EVENT_TYPES() 

class MyThread : public wxThread 
{ 
    public: 
     MyThread(wxEvtHandler* pParent, int param); 
    private: 
     int m_param; 
     void* Entry(); 
    protected: 
     wxEvtHandler* m_pParent; 
}; 
#endif 

MyThread.cpp

#include "MyThread.h" 
DEFINE_EVENT_TYPE(wxEVT_MYTHREAD) 
MyThread::MyThread(wxEvtHandler* pParent, int param) : wxThread(wxTHREAD_DETACHED), m_pParent(pParent) 
{ 
    //pass parameters into the thread 
m_param = param; 
} 
void* MyThread::Entry() 
{ 
    wxCommandEvent evt(wxEVT_MYTHREAD, GetId()); 
    //can be used to set some identifier for the data 
    evt.SetInt(r); 
    //whatever data your thread calculated, to be returned to GUI 
    evt.SetClientData(data); 
    wxPostEvent(m_pParent, evt); 
    return 0; 
} 

我覺得這比維基提供的更清晰,簡潔的例子。顯然,我遺漏了有關實際啓動應用程序的代碼(wx約定會使MyApp.cpp)以及任何其他與線程無關的代碼。

0

如果你的程序很簡單,並且你不想亂搞線程,你可以考慮定期在你的long函數中調用wxWindow :: Update()

2

從實施上述的一些技巧:

  1. 使用MINGW32和代碼塊,我有以下warning: EVENT redeclared without dllimport attribute: previous dllimport ignored。如果您不需要導出活動,請使用DEFINE_LOCAL_EVENT_TYPEDECLARE_LOCAL_EVENT_TYPE(而不是DEFINE_EVENT_TYPEDECLARE_EVENT_TYPE)。

  2. 如果要通過SetClientData()傳遞對象,請確保在可拆卸線程中使用new運算符創建數據。一旦複製數據,調用應用程序將必須複製delete數據。

例如:

BEGIN_DECLARE_EVENT_TYPES() 
    DECLARE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD, -1) 
END_DECLARE_EVENT_TYPES() 

void* MyThread::Entry() 
{ 
    wxCommandEvent evt(wxEVT_CALC_THREAD, GetId()); 
    // do some work 
    vector<map<int, int> > *vm = new vector<map<int, int> >(); 
    // perform operations with the object vm ... 
    evt.SetClientData((void*)vm); 
    wxPostEvent(m_pParent, evt); 
} 

,並在調用應用程序:

DEFINE_LOCAL_EVENT_TYPE(wxEVT_CALC_THREAD) 

// change this to your event table 
BEGIN_EVENT_TABLE(..., ...) 
    EVT_COMMAND(wxID_ANY, wxEVT_CALC_THREAD, ThreadDone) 
END_EVENT_TABLE() 

void ThreadDone(wxCommandEvent& event) 
{ 

    vector<map<int, int> > *temp = (vector<map<int, int> > *)event.GetClientData(); 
    // store the data in *temp 
    delete temp; 
}