+ By default wxThreads in wxWidgets use the @b detached behavior.
+ Detached threads delete themselves once they have completed, either by themselves
+ when they complete processing or through a call to Delete(), and thus
+ @b must be created on the heap (through the new operator, for example).
+
+ Typically you'll want to store the instances of the detached wxThreads you
+ allocate, so that you can call functions on them.
+ Because of their nature however you'll need to always use a critical section
+ when accessing them:
+
+ @code
+ // declare a new type of event, to be used by our MyThread class:
+ extern const wxEventType wxEVT_COMMAND_MYTHREAD_COMPLETED;
+
+ class MyThread : public wxThread
+ {
+ public:
+ MyThread(wxEvtHandler *handler) : wxThread(wxTHREAD_DETACHED)
+ { m_pHandler = handler; }
+
+ ExitCode Entry()
+ {
+ while (!TestDestroy())
+ {
+ // ... do a bit of work...
+ }
+
+ // signal the event handler that this thread is going to be destroyed
+ // NOTE: here we assume that using the m_pHandler pointer is safe,
+ // (in this case it's assured by the MyFrame destructor)
+ wxQueueEvent(m_pHandler, new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
+
+ return (ExitCode)0; // success
+ }
+
+ wxEvtHandler *m_pHandler;
+ };
+
+ class MyFrame : public wxFrame
+ {
+ public:
+ ...
+ ~MyFrame();
+ ...
+ void DoStartThread();
+ void DoPauseThread();
+
+ // a resume routine would be mostly identic to DoPauseThread()
+ void DoResumeThread() { ... }
+
+ void OnThreadExit(wxCommandEvent&);
+
+ protected:
+ MyThread *m_pThread;
+
+ // this is _required_ for writing safe code!
+ wxCriticalSection m_critSection;
+ };
+
+ void MyFrame::DoStartThread()
+ {
+ m_pThread = new wxThread();
+
+ if ( m_pThread->Create() != wxTHREAD_NO_ERROR )
+ {
+ wxLogError("Can't create the thread!");
+ delete m_pThread;
+ m_pThread = NULL;
+ }
+ else
+ {
+ if (m_pThread->Run() != wxTHREAD_NO_ERROR )
+ {
+ wxLogError("Can't create the thread!");
+ delete m_pThread;
+ m_pThread = NULL;
+ }
+
+ // after the call to wxThread::Run(), the m_pThread pointer is "unsafe":
+ // at any moment the thread may cease to exist (because it completes its work).
+ // To avoid dangling pointers OnThreadExit() will set m_pThread
+ // to NULL when the thread dies.
+ }
+ }
+
+ void MyFrame::OnThreadExit(wxCommandEvent&)
+ {
+ // the thread just ended; make sure not to leave dangling pointers around
+ m_pThread = NULL;
+ }
+
+ void MyFrame::DoPauseThread()
+ {
+ // anytime we access the m_pThread pointer we must ensure that it won't
+ // be modified in the meanwhile; inside a critical section we are sure
+ // that we are the only thread running, so that's what we need.
+ wxCriticalSectionLocker enter(m_critSection);
+
+ if (m_pThread) // does the thread still exist?
+ {
+ // without a critical section, once reached this point it may happen
+ // that the OS scheduler gives control to the MyThread::Entry() function,
+ // which in turn may return (because it completes its work) making
+ // invalid the m_pThread pointer; the critical section above
+ // makes this code safe.
+
+ if (m_pThread->Pause() != wxTHREAD_NO_ERROR )
+ wxLogError("Can't pause the thread!");
+ }
+ }
+
+ MyFrame::~MyFrame()
+ {
+ wxCriticalSectionLocker enter(m_critSection);
+
+ if (m_pThread) // does the thread still exist?
+ {
+ if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
+ wxLogError("Can't delete the thread!");
+
+ // as soon as we exit the critical section and the MyThread::Entry
+ // function calls TestDestroy(), the thread will exit and thus
+ // call OnExitThread(); we need to maintain MyFrame object alive
+ // until then:
+ wxEventLoopBase* p = wxEventLoopBase::GetActive();
+ while (p->Pending() && m_pThread)
+ p->Dispatch();
+
+ // the wxEVT_COMMAND_MYTHREAD_COMPLETED event was posted, we can
+ // safely exit
+ }
+ }
+ @endcode
+
+ Conversely, @b joinable threads do not delete themselves when they are done