+// ----------------------------------------------------------------------------
+// wxThreadHelper: this class implements the threading logic to run a
+// background task in another object (such as a window). It is a mix-in: just
+// derive from it to implement a threading background task in your class.
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_BASE wxThreadHelper
+{
+private:
+ void KillThread()
+ {
+ // If wxThreadHelperThread is detached and is about to finish, it will
+ // set m_thread to NULL so don't delete it then.
+ // But if KillThread is called before wxThreadHelperThread (in detached mode)
+ // sets it to NULL, then the thread object still exists and can be killed
+ wxCriticalSectionLocker locker(m_critSection);
+
+ if ( m_thread )
+ {
+ m_thread->Kill();
+
+ if ( m_kind == wxTHREAD_JOINABLE )
+ delete m_thread;
+
+ m_thread = NULL;
+ }
+ }
+
+public:
+ // constructor only initializes m_thread to NULL
+ wxThreadHelper(wxThreadKind kind = wxTHREAD_JOINABLE)
+ : m_thread(NULL), m_kind(kind) { }
+
+ // destructor deletes m_thread
+ virtual ~wxThreadHelper() { KillThread(); }
+
+#if WXWIN_COMPATIBILITY_2_8
+ wxDEPRECATED( wxThreadError Create(unsigned int stackSize = 0) );
+#endif
+
+ // create a new thread (and optionally set the stack size on platforms that
+ // support/need that), call Run() to start it
+ wxThreadError CreateThread(wxThreadKind kind = wxTHREAD_JOINABLE,
+ unsigned int stackSize = 0)
+ {
+ KillThread();
+
+ m_kind = kind;
+ m_thread = new wxThreadHelperThread(*this, m_kind);
+
+ return m_thread->Create(stackSize);
+ }
+
+ // entry point for the thread - called by Run() and executes in the context
+ // of this thread.
+ virtual void *Entry() = 0;
+
+ // returns a pointer to the thread which can be used to call Run()
+ wxThread *GetThread() const
+ {
+ wxCriticalSectionLocker locker((wxCriticalSection&)m_critSection);
+
+ wxThread* thread = m_thread;
+
+ return thread;
+ }
+
+protected:
+ wxThread *m_thread;
+ wxThreadKind m_kind;
+ wxCriticalSection m_critSection; // To guard the m_thread variable
+
+ friend class wxThreadHelperThread;
+};
+
+#if WXWIN_COMPATIBILITY_2_8
+inline wxThreadError wxThreadHelper::Create(unsigned int stackSize)
+{ return CreateThread(m_kind, stackSize); }
+#endif
+
+// call Entry() in owner, put it down here to avoid circular declarations
+inline void *wxThreadHelperThread::Entry()
+{
+ void * const result = m_owner.Entry();
+
+ wxCriticalSectionLocker locker(m_owner.m_critSection);
+
+ // Detached thread will be deleted after returning, so make sure
+ // wxThreadHelper::GetThread will not return an invalid pointer.
+ // And that wxThreadHelper::KillThread will not try to kill
+ // an already deleted thread
+ if ( m_owner.m_kind == wxTHREAD_DETACHED )
+ m_owner.m_thread = NULL;
+
+ return result;
+}
+