- synchronization objects such as mutexes() or @ref wxCriticalSection
- "critical sections" is recommended. In addition, don't create global thread
- objects because they allocate memory in their constructor, which will cause
- problems for the memory checking system.
-
- @section overview_typeswxthread Types of wxThreads
- There are two types of threads in wxWidgets: @e detached and @e joinable,
- modeled after the the POSIX thread API. This is different from the Win32 API
- where all threads are joinable.
-
- By default wxThreads in wxWidgets use the 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
- must be created on the heap (through the new operator, for example).
- Conversely, joinable threads do not delete themselves when they are done
- processing and as such are safe to create on the stack. Joinable threads
- also provide the ability for one to get value it returned from Entry()
- through Wait().
-
- You shouldn't hurry to create all the threads joinable, however, because this
- has a disadvantage as well: you @b must Wait() for a joinable thread or the
- system resources used by it will never be freed, and you also must delete the
- corresponding wxThread object yourself if you did not create it on the stack.
- In contrast, detached threads are of the "fire-and-forget" kind: you only have to
- start a detached thread and it will terminate and destroy itself.
-
- @section overview_deletionwxthread wxThread Deletion
- Regardless of whether it has terminated or not, you should call
- Wait() on a joinable thread to release its memory, as outlined in
- @ref overview_typeswxthread "Types of wxThreads". If you created
- a joinable thread on the heap, remember to delete it manually with the delete
- operator or similar means as only detached threads handle this type of memory
- management.
-
- Since detached threads delete themselves when they are finished processing,
- you should take care when calling a routine on one. If you are certain the
- thread is still running and would like to end it, you may call Delete()
- to gracefully end it (which implies that the thread will be deleted after
- that call to Delete()). It should be implied that you should never attempt
- to delete a detached thread with the delete operator or similar means.
- As mentioned, Wait() or Delete() attempts to gracefully terminate a
- joinable and detached thread, respectively. It does this by waiting until
- the thread in question calls TestDestroy() or ends processing (returns
- from wxThread::Entry).
-
- Obviously, if the thread does call TestDestroy() and does not end the calling
- thread will come to halt. This is why it is important to call TestDestroy() in
- the Entry() routine of your threads as often as possible.
- As a last resort you can end the thread immediately through Kill(). It is
- strongly recommended that you do not do this, however, as it does not free
- the resources associated with the object (although the wxThread object of
- detached threads will still be deleted) and could leave the C runtime
- library in an undefined state.
-
- @section overview_secondarythreads wxWidgets Calls in Secondary Threads
- All threads other than the "main application thread" (the one
- wxApp::OnInit or your main function runs in, for example) are considered
- "secondary threads". These include all threads created by Create() or the
- corresponding constructors.
-
- GUI calls, such as those to a wxWindow or wxBitmap are explicitly not safe
- at all in secondary threads and could end your application prematurely.
- This is due to several reasons, including the underlying native API and
- the fact that wxThread does not run a GUI event loop similar to other APIs
- as MFC.
-
- A workaround for some wxWidgets ports is calling wxMutexGUIEnter()
- before any GUI calls and then calling wxMutexGUILeave() afterwords. However,
- the recommended way is to simply process the GUI calls in the main thread
- through an event that is posted by either wxQueueEvent().
- This does not imply that calls to these classes are thread-safe, however,
- as most wxWidgets classes are not thread-safe, including wxString.
-
- @section overview_pollwxThread Don't Poll a wxThread
- A common problem users experience with wxThread is that in their main thread
- they will check the thread every now and then to see if it has ended through
- IsRunning(), only to find that their application has run into problems
- because the thread is using the default behavior and has already deleted
- itself. Naturally, they instead attempt to use joinable threads in place
- of the previous behavior. However, polling a wxThread for when it has ended
- is in general a bad idea - in fact calling a routine on any running wxThread
- should be avoided if possible. Instead, find a way to notify yourself when
- the thread has ended.
-
- Usually you only need to notify the main thread, in which case you can
- post an event to it via wxPostEvent() or wxEvtHandler::AddPendingEvent.
- In the case of secondary threads you can call a routine of another class
- when the thread is about to complete processing and/or set the value of
- a variable, possibly using mutexes() and/or other synchronization means
- if necessary.
+ synchronization objects such as mutexes (see wxMutex) or critical sections
+ (see wxCriticalSection) is recommended.
+ In addition, don't create global thread objects because they allocate memory
+ in their constructor, which will cause problems for the memory checking system.
+
+
+ @section thread_types Types of wxThreads
+
+ There are two types of threads in wxWidgets: @e detached and @e joinable,
+ modeled after the POSIX thread API. This is different from the Win32 API
+ where all threads are joinable.
+
+ By default wxThreads in wxWidgets use the @b detached behaviour.
+ 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:
+ wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
+ wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
+ class MyFrame;
+
+ class MyThread : public wxThread
+ {
+ public:
+ MyThread(MyFrame *handler)
+ : wxThread(wxTHREAD_DETACHED)
+ { m_pHandler = handler }
+ ~MyThread();
+
+ protected:
+ virtual ExitCode Entry();
+ MyFrame *m_pHandler;
+ };
+
+ class MyFrame : public wxFrame
+ {
+ public:
+ ...
+ ~MyFrame()
+ {
+ // it's better to do any thread cleanup in the OnClose()
+ // event handler, rather than in the destructor.
+ // This is because the event loop for a top-level window is not
+ // active anymore when its destructor is called and if the thread
+ // sends events when ending, they won't be processed unless
+ // you ended the thread from OnClose.
+ // See @ref overview_windowdeletion for more info.
+ }
+ ...
+ void DoStartThread();
+ void DoPauseThread();
+
+ // a resume routine would be nearly identic to DoPauseThread()
+ void DoResumeThread() { ... }
+
+ void OnThreadUpdate(wxThreadEvent&);
+ void OnThreadCompletion(wxThreadEvent&);
+ void OnClose(wxCloseEvent&);
+
+ protected:
+ MyThread *m_pThread;
+ wxCriticalSection m_pThreadCS; // protects the m_pThread pointer
+
+ wxDECLARE_EVENT_TABLE();
+ };
+
+ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
+ EVT_CLOSE(MyFrame::OnClose)
+ EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
+ EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
+ EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
+ wxEND_EVENT_TABLE()
+
+ wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent)
+ wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent)
+
+ void MyFrame::DoStartThread()
+ {
+ m_pThread = new MyThread(this);
+
+ 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.
+ }
+ }
+
+ wxThread::ExitCode MyThread::Entry()
+ {
+ while (!TestDestroy())
+ {
+ // ... do a bit of work...
+
+ wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
+ }
+
+ // 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 this is assured by the MyFrame destructor)
+ wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
+
+ return (wxThread::ExitCode)0; // success
+ }
+
+ MyThread::~MyThread()
+ {
+ wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
+
+ // the thread is being destroyed; make sure not to leave dangling pointers around
+ m_pHandler->m_pThread = NULL;
+ }
+
+ void MyFrame::OnThreadCompletion(wxThreadEvent&)
+ {
+ wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
+ }
+
+ void MyFrame::OnThreadUpdate(wxThreadEvent&)
+ {
+ wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
+ }
+
+ void MyFrame::DoPauseThread()
+ {
+ // anytime we access the m_pThread pointer we must ensure that it won't
+ // be modified in the meanwhile; since only a single thread may be
+ // inside a given critical section at a given time, the following code
+ // is safe:
+ wxCriticalSectionLocker enter(m_pThreadCS);
+
+ 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
+
+ if (m_pThread->Pause() != wxTHREAD_NO_ERROR )
+ wxLogError("Can't pause the thread!");
+ }
+ }
+
+ void MyFrame::OnClose(wxCloseEvent&)
+ {
+ {
+ wxCriticalSectionLocker enter(m_pThreadCS);
+
+ if (m_pThread) // does the thread still exist?
+ {
+ wxMessageOutputDebug().Printf("MYFRAME: deleting thread");
+
+ if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
+ wxLogError("Can't delete the thread!");
+ }
+ } // exit from the critical section to give the thread
+ // the possibility to enter its destructor
+ // (which is guarded with m_pThreadCS critical section!)
+
+ while (1)
+ {
+ { // was the ~MyThread() function executed?
+ wxCriticalSectionLocker enter(m_pThreadCS);
+ if (!m_pThread) break;
+ }
+
+ // wait for thread completion
+ wxThread::This()->Sleep(1);
+ }
+
+ Destroy();
+ }
+ @endcode
+
+ For a more detailed and comprehensive example, see @sample{thread}.
+ For a simpler way to share data and synchronization objects between
+ the main and the secondary thread see wxThreadHelper.
+
+ Conversely, @b joinable threads do not delete themselves when they are done
+ processing and as such are safe to create on the stack. Joinable threads
+ also provide the ability for one to get value it returned from Entry()
+ through Wait().
+ You shouldn't hurry to create all the threads joinable, however, because this
+ has a disadvantage as well: you @b must Wait() for a joinable thread or the
+ system resources used by it will never be freed, and you also must delete the
+ corresponding wxThread object yourself if you did not create it on the stack.
+ In contrast, detached threads are of the "fire-and-forget" kind: you only have
+ to start a detached thread and it will terminate and destroy itself.
+
+
+ @section thread_deletion wxThread Deletion
+
+ Regardless of whether it has terminated or not, you should call Wait() on a
+ @b joinable thread to release its memory, as outlined in @ref thread_types.
+ If you created a joinable thread on the heap, remember to delete it manually
+ with the @c delete operator or similar means as only detached threads handle
+ this type of memory management.
+
+ Since @b detached threads delete themselves when they are finished processing,
+ you should take care when calling a routine on one. If you are certain the
+ thread is still running and would like to end it, you may call Delete()
+ to gracefully end it (which implies that the thread will be deleted after
+ that call to Delete()). It should be implied that you should @b never attempt
+ to delete a detached thread with the @c delete operator or similar means.
+
+ As mentioned, Wait() or Delete() functions attempt to gracefully terminate a
+ joinable and a detached thread, respectively. They do this by waiting until
+ the thread in question calls TestDestroy() or ends processing (i.e. returns
+ from wxThread::Entry).
+
+ Obviously, if the thread does call TestDestroy() and does not end, the
+ thread which called Wait() or Delete() will come to halt.
+ This is why it's important to call TestDestroy() in the Entry() routine of
+ your threads as often as possible and immediately exit when it returns @true.
+
+ As a last resort you can end the thread immediately through Kill(). It is
+ strongly recommended that you do not do this, however, as it does not free
+ the resources associated with the object (although the wxThread object of
+ detached threads will still be deleted) and could leave the C runtime
+ library in an undefined state.
+
+
+ @section thread_secondary wxWidgets Calls in Secondary Threads
+
+ All threads other than the "main application thread" (the one running
+ wxApp::OnInit() or the one your main function runs in, for example) are
+ considered "secondary threads". These include all threads created by Create()
+ or the corresponding constructors.
+
+ GUI calls, such as those to a wxWindow or wxBitmap are explicitly not safe
+ at all in secondary threads and could end your application prematurely.
+ This is due to several reasons, including the underlying native API and
+ the fact that wxThread does not run a GUI event loop similar to other APIs
+ as MFC.
+
+ A workaround for some wxWidgets ports is calling wxMutexGUIEnter()
+ before any GUI calls and then calling wxMutexGUILeave() afterwords.
+ However, the recommended way is to simply process the GUI calls in the main
+ thread through an event that is posted by wxQueueEvent().
+ This does not imply that calls to these classes are thread-safe, however,
+ as most wxWidgets classes are not thread-safe, including wxString.
+
+
+ @section thread_poll Don't Poll a wxThread
+
+ A common problem users experience with wxThread is that in their main thread
+ they will check the thread every now and then to see if it has ended through
+ IsRunning(), only to find that their application has run into problems
+ because the thread is using the default behaviour (i.e. it's @b detached) and
+ has already deleted itself.
+ Naturally, they instead attempt to use joinable threads in place of the previous
+ behaviour. However, polling a wxThread for when it has ended is in general a
+ bad idea - in fact calling a routine on any running wxThread should be avoided
+ if possible. Instead, find a way to notify yourself when the thread has ended.
+
+ Usually you only need to notify the main thread, in which case you can
+ post an event to it via wxQueueEvent().
+ In the case of secondary threads you can call a routine of another class
+ when the thread is about to complete processing and/or set the value of
+ a variable, possibly using mutexes (see wxMutex) and/or other synchronization
+ means if necessary.