+
+ wxThread::ExitCode MyFrame::Entry()
+ {
+ // IMPORTANT:
+ // this function gets executed in the secondary thread context!
+
+ int offset = 0;
+
+ // here we do our long task, periodically calling TestDestroy():
+ while (!GetThread()->TestDestroy())
+ {
+ // since this Entry() is implemented in MyFrame context we don't
+ // need any pointer to access the m_data, m_processedData, m_dataCS
+ // variables... very nice!
+
+ // this is an example of the generic structure of a download thread:
+ char buffer[1024];
+ download_chunk(buffer, 1024); // this takes time...
+
+ {
+ // ensure no one reads m_data while we write it
+ wxCriticalSectionLocker lock(m_dataCS);
+ memcpy(m_data+offset, buffer, 1024);
+ offset += 1024;
+ }
+
+
+ // VERY IMPORTANT: do not call any GUI function inside this
+ // function; rather use wxQueueEvent():
+ wxQueueEvent(this, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
+ // we used pointer 'this' assuming it's safe; see OnClose()
+ }
+
+ // TestDestroy() returned true (which means the main thread asked us
+ // to terminate as soon as possible) or we ended the long task...
+ return (wxThread::ExitCode)0;
+ }
+
+ void MyFrame::OnClose(wxCloseEvent&)
+ {
+ // important: before terminating, we _must_ wait for our joinable
+ // thread to end, if it's running; in fact it uses variables of this
+ // instance and posts events to *this event handler
+
+ if (GetThread() && // DoStartALongTask() may have not been called
+ GetThread()->IsRunning())
+ GetThread()->Wait();
+
+ Destroy();
+ }
+
+ void MyFrame::OnThreadUpdate(wxThreadEvent& evt)
+ {
+ // ...do something... e.g. m_pGauge->Pulse();
+
+ // read some parts of m_data just for fun:
+ wxCriticalSectionLocker lock(m_dataCS);
+ wxPrintf("%c", m_data[100]);
+ }