diff --git a/docs/changes.txt b/docs/changes.txt index 7a74e203cd..955902973e 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -59,6 +59,7 @@ All: - added support for POST method and alt ports to wxHTTP (Roger Chickering) - added wxSocket::IPAddress() (Chris Mellon) - wxDataStreams can read/write many elements at once (Mickael Gilabert) +- added wxThreadHelper class (Daniel Howard) wxBase: diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex index 0959dd071b..d7a3979c84 100644 --- a/docs/latex/wx/category.tex +++ b/docs/latex/wx/category.tex @@ -500,6 +500,7 @@ capabilities of the various platforms. \twocolwidtha{6cm} \begin{twocollist}\itemsep=0pt \twocolitem{\helpref{wxThread}{wxthread}}{Thread class} +\twocolitem{\helpref{wxThreadHelper}{wxthreadhelper}}{Manages background threads easily} \twocolitem{\helpref{wxMutex}{wxmutex}}{Mutex class} \twocolitem{\helpref{wxMutexLocker}{wxmutexlocker}}{Mutex locker utility class} \twocolitem{\helpref{wxCriticalSection}{wxcriticalsection}}{Critical section class} diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index a8d555ce31..d39d3372ee 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -295,6 +295,8 @@ \input txtstrm.tex \input valtext.tex \input thread.tex +\input threadh.tex +\input threadht.tex \input timer.tex \input timespan.tex \input tipprov.tex diff --git a/docs/latex/wx/threadh.tex b/docs/latex/wx/threadh.tex new file mode 100644 index 0000000000..729f51015c --- /dev/null +++ b/docs/latex/wx/threadh.tex @@ -0,0 +1,100 @@ +\section{\class{wxThreadHelper}}\label{wxthreadhelper} + +The wxThreadHelper class is a mix-in class that manages a single background +thread. By deriving from wxThreadHelper, a class can implement the thread +code in its own \helpref{wxThreadHelper::Entry}{wxthreadhelperentry} method +and easily share data and synchronization objects between the main thread +and the worker thread. Doing this prevents the awkward passing of pointers +that is needed when the original object in the main thread needs to +synchronize with its worker thread in its own wxThread derived object. + +For example, \helpref{wxFrame}{wxframe} may need to make some calculations +in a background thread and then display the results of those calculations in +the main window. + +Ordinarily, a \helpref{wxThread}{wxthread} derived object would be created +with the calculation code implemented in +\helpref{wxThread::Entry}{wxthreadentry}. To access the inputs to the +calculation, the frame object would often to pass a pointer to itself to the +thread object. Similiarly, the frame object would hold a pointer to the +thread object. Shared data and synchronization objects could be stored in +either object though the object without the data would have to access the +data through a pointer. + +However, with wxThreadHelper, the frame object and the thread object are +treated as the same object. Shared data and synchronization variables are +stored in the single object, eliminating a layer of indirection and the +associated pointers. + +\wxheading{Derived from} + +None. + +\wxheading{Include files} + + + +\wxheading{See also} + +\helpref{wxThread}{wxthread}, \helpref{wxThreadHelperThread}{wxthreadhelperthread} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxThreadHelper::wxThreadHelper}\label{wxthreadhelperctor} + +\func{}{wxThreadHelper}{\void} + +This constructor simply initializes a member variable. + +\membersection{wxThreadHelper::m\_thread} + +\member{wxThread *}{m\_thread} + +the actual \helpref{wxThread}{wxthread} object. + +\membersection{wxThread::\destruct{wxThreadHelper}} + +\func{}{\destruct{wxThreadHelper}}{\void} + +The destructor frees the resources associated with the thread. + +\membersection{wxThreadHelper::Create}\label{wxthreadhelpercreate} + +\func{wxThreadError}{Create}{\param{unsigned int }{stackSize = 0}} + +Creates a new thread. The thread object is created in the suspended state, and you +should call \helpref{GetThread()->Run()}{wxthreadhelperthreadrun} to start running +it. You may optionally specify the stack size to be allocated to it (Ignored on +platforms that don't support setting it explicitly, eg. Unix). + +\wxheading{Return value} + +One of: + +\twocolwidtha{7cm} +\begin{twocollist}\itemsep=0pt +\twocolitem{{\bf wxTHREAD\_NO\_ERROR}}{There was no error.} +\twocolitem{{\bf wxTHREAD\_NO\_RESOURCE}}{There were insufficient resources to create a new thread.} +\twocolitem{{\bf wxTHREAD\_RUNNING}}{The thread is already running.} +\end{twocollist} + +\membersection{wxThreadHelper::Entry}\label{wxthreadhelperentry} + +\func{virtual ExitCode}{Entry}{\void} + +This is the entry point of the thread. This function is pure virtual and must +be implemented by any derived class. The thread execution will start here. + +The returned value is the thread exit code which is only useful for +joinable threads and is the value returned by +\helpref{GetThread()->Wait()}{wxthreadwait}. + +This function is called by wxWindows itself and should never be called +directly. + +\membersection{wxThreadHelper::GetThread}\label{wxthreadhelpergetthread} + +\func{wxThread *}{GetThread}{\void} + +This is a public function that returns the \helpref{wxThread}{wxthread} object +associated with the thread. diff --git a/docs/latex/wx/threadht.tex b/docs/latex/wx/threadht.tex new file mode 100644 index 0000000000..87987662d8 --- /dev/null +++ b/docs/latex/wx/threadht.tex @@ -0,0 +1,74 @@ +\section{\class{wxThreadHelperThread}}\label{wxThreadHelperThread} + +The wxThreadHelperThread class is used internally by the +\helpref{wxThreadHelper}{wxthreadhelper} mix-in class. This class simply +turns around and calls \helpref{wxThreadHelper::Entry}{wxthreadhelperentry} +in its owner class when the thread runs. + +\wxheading{Derived from} + +\helpref{wxThread}{wxthread} + +\wxheading{Include files} + + + +\wxheading{See also} + +\helpref{wxThread}{wxthread}, \helpref{wxThreadHelper}{wxthreadhelper} + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxThreadHelperThread::wxThreadHelperThread}\label{wxthreadctor} + +\func{}{wxThreadHelperThread}{\void} + +This constructor simply initializes member variables. + +\membersection{wxThreadHelperThread::m\_owner} + +\member{wxThreadHelperThread\& }{m\_owner} + +the \helpref{wxThreadHelper}{wxthreadhelper} object which holds the code to +run inside the thread. + +\membersection{wxThreadHelperThread::Entry}\label{wxthreadhelperthreadentry} + +\func{virtual ExitCode}{Entry}{\void} + +This is the entry point of the thread. This function eventually calls +\helpref{wxThreadHelper::Entry}{wxthreadhelperentry}. The actual worker +thread code should be implemented in +\helpref{wxThreadHelper::Entry}{wxthreadhelperentry}, not here, so all +shared data and synchronization objects can be shared easily between the +main thread and the worker thread. + +The returned value is the thread exit code which is the value returned by +\helpref{Wait()}{wxthreadwait}. + +This function is called by wxWindows itself and should never be called +directly. + +\membersection{wxThreadHelperThread::CallEntry}\label{wxthreadhelperthreadcallentry} + +\func{virtual ExitCode}{CallEntry}{\void} + +This is a convenience method that actually calls +\helpref{wxThreadHelper::Entry}{wxthreadhelperentry}. This function +eventually calls \helpref{wxThreadHelper::Entry}{wxthreadhelperentry}. +The actual worker thread code should be implemented in +\helpref{wxThreadHelper::Entry}{wxthreadhelperentry}, not here, so all +shared data and synchronization objects can be shared easily between the +main thread and the worker thread. + +It must be declared after \helpref{wxThreadHelper}{wxthreadhelper} so it +can access \helpref{wxThreadHelper::Entry}{wxthreadhelperentry} and avoid +circular dependencies. Thus, it uses the inline keyword to allow its +definition outside of the class definition. To avoid any conflicts +between the virtual and inline keywords, it is a non-virtual method. + +The returned value is the thread exit code which is the value returned by +\helpref{Wait()}{wxthreadwait}. + +This function is called by wxWindows itself and should never be called +directly. diff --git a/include/wx/thread.h b/include/wx/thread.h index 24046e1d5a..543f16ceda 100644 --- a/include/wx/thread.h +++ b/include/wx/thread.h @@ -114,6 +114,7 @@ enum wxMutexType }; // forward declarations +class WXDLLIMPEXP_BASE wxThreadHelper; class WXDLLIMPEXP_BASE wxConditionInternal; class WXDLLIMPEXP_BASE wxMutexInternal; class WXDLLIMPEXP_BASE wxSemaphoreInternal; @@ -581,6 +582,84 @@ private: bool m_isDetached; }; +// wxThreadHelperThread class +// -------------------------- + +class WXDLLIMPEXP_BASE wxThreadHelperThread : public wxThread +{ +public: + // constructor only creates the C++ thread object and doesn't create (or + // start) the real thread + wxThreadHelperThread(wxThreadHelper& owner) + : wxThread(wxTHREAD_JOINABLE), m_owner(owner) + { } + +protected: + // entry point for the thread -- calls Entry() in owner. + virtual void *Entry(); + +private: + // the owner of the thread + wxThreadHelper& m_owner; + + // no copy ctor/assignment operator + wxThreadHelperThread(const wxThreadHelperThread&); + wxThreadHelperThread& operator=(const wxThreadHelperThread&); +}; + +// ---------------------------------------------------------------------------- +// 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 ( m_thread ) + { + m_thread->Kill(); + delete m_thread; + } + } + +public: + // constructor only initializes m_thread to NULL + wxThreadHelper() : m_thread(NULL) { } + + // destructor deletes m_thread + virtual ~wxThreadHelper() { KillThread(); } + + // create a new thread (and optionally set the stack size on platforms that + // support/need that), call Run() to start it + wxThreadError Create(unsigned int stackSize = 0) + { + KillThread(); + + m_thread = new wxThreadHelperThread(*this); + + 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 { return m_thread; } + +protected: + wxThread *m_thread; +}; + +// call Entry() in owner, put it down here to avoid circular declarations +inline void *wxThreadHelperThread::Entry() +{ + return m_owner.Entry(); +} + // ---------------------------------------------------------------------------- // Automatic initialization // ----------------------------------------------------------------------------