From 24d54fca53a61504b3b0072a78b00e18c9daac3b Mon Sep 17 00:00:00 2001 From: crs Date: Sun, 28 Jul 2002 13:34:19 +0000 Subject: [PATCH] Added doxygen comments for all relevant headers in mt. --- mt/CCondVar.h | 135 +++++++++++++++++++------ mt/CLock.h | 10 ++ mt/CMutex.h | 47 +++++++-- mt/CThread.h | 252 ++++++++++++++++++++++++++++++++-------------- mt/CThreadRep.h | 1 + mt/CTimerThread.h | 15 ++- mt/XThread.h | 28 ++++-- 7 files changed, 364 insertions(+), 124 deletions(-) diff --git a/mt/CCondVar.h b/mt/CCondVar.h index 1cf9f491..af9d88dd 100644 --- a/mt/CCondVar.h +++ b/mt/CCondVar.h @@ -6,44 +6,97 @@ class CStopwatch; +//! Generic condition variable +/*! +This class provides functionality common to all condition variables +but doesn't provide the actual variable storage. A condition variable +is a multiprocessing primitive that can be waited on. Every condition +variable has an associated mutex. +*/ class CCondVarBase { public: - // mutex must be supplied. all condition variables have an - // associated mutex. + /*! + \c mutex must not be NULL. All condition variables have an + associated mutex. The mutex needn't be unique to one condition + variable. + */ CCondVarBase(CMutex* mutex); ~CCondVarBase(); - // manipulators + //! @name manipulators + //@{ - // lock/unlock the mutex. see CMutex. + //! Lock the condition variable's mutex + /*! + Lock the condition variable's mutex. The condition variable should + be locked before reading or writing it. It must be locked for a + call to wait(). Locks are not recursive; locking a locked mutex + will deadlock the thread. + */ void lock() const; + + //! Unlock the condition variable's mutex void unlock() const; - // signal the condition. Signal() wakes one waiting thread. - // Broadcast() wakes all waiting threads. + //! Signal the condition variable + /*! + Wake up one waiting thread, if there are any. Which thread gets + woken is undefined. + */ void signal(); + + //! Signal the condition variable + /*! + Wake up all waiting threads, if any. + */ void broadcast(); - // accessors + //@} + //! @name accessors + //@{ - // wait on the condition. if timeout < 0 then wait until signalled, - // otherwise up to timeout seconds or until signalled, whichever - // comes first. since clients normally wait on condition variables - // in a loop, clients can provide a CStopwatch that acts as the - // timeout clock. using it, clients don't have to recalculate the - // timeout on each iteration. passing a stopwatch with a negative - // timeout is pointless but permitted. - // - // returns true if the object was signalled during the wait, false - // otherwise. - // - // (cancellation point) + //! Wait on the condition variable + /*! + Wait on the condition variable. If \c timeout < 0 then wait until + signalled, otherwise up to \c timeout seconds or until signalled, + whichever comes first. Returns true if the object was signalled + during the wait, false otherwise. + + The proper way to wait for a condition is: + \code + cv.lock(); + while (cv-expr) { + cv.wait(); + } + cv.unlock(); + \endcode + where \c cv-expr involves the value of \c cv and is false when the + condition is satisfied. + + (cancellation point) + */ bool wait(double timeout = -1.0) const; - bool wait(CStopwatch&, double timeout) const; - // get the mutex passed to the c'tor + //! Wait on the condition variable + /*! + Same as \c wait(double) but use \c timer to compare against \timeout. + Since clients normally wait on condition variables in a loop, clients + can use this to avoid recalculating \c timeout on each iteration. + Passing a stopwatch with a negative \c timeout is pointless (it will + never time out) but permitted. + + (cancellation point) + */ + bool wait(CStopwatch& timer, double timeout) const; + + //! Get the mutex + /*! + Get the mutex passed to the c'tor. + */ CMutex* getMutex() const; + //@} + private: void init(); void fini(); @@ -63,27 +116,49 @@ private: #endif }; +//! Condition variable +/*! +A condition variable with storage for type \c T. +*/ template class CCondVar : public CCondVarBase { public: - CCondVar(CMutex* mutex, const T&); + //! Initialize using \c value + CCondVar(CMutex* mutex, const T& value); + //! Initialize using another condition variable's value CCondVar(const CCondVar&); ~CCondVar(); - // manipulators + //! @name manipulators + //@{ - // assigns the value of the variable - CCondVar& operator=(const CCondVar&); + //! Assigns the value of \c cv to this + /*! + Set the variable's value. The condition variable should be locked + before calling this method. + */ + CCondVar& operator=(const CCondVar& cv); - // assign the value - CCondVar& operator=(const T&); + //! Assigns \c value to this + /*! + Set the variable's value. The condition variable should be locked + before calling this method. + */ + CCondVar& operator=(const T& v); - // accessors + //@} + //! @name accessors + //@{ - // get the const value. this object should be locked before - // calling this method. + //! Get the variable's value + /*! + Get the variable's value. The condition variable should be locked + before calling this method. + */ operator const T&() const; + //@} + private: T m_data; }; diff --git a/mt/CLock.h b/mt/CLock.h index 2044855c..5e12f73e 100644 --- a/mt/CLock.h +++ b/mt/CLock.h @@ -4,10 +4,20 @@ class CMutex; class CCondVarBase; +//! Mutual exclusion lock utility +/*! +This class locks a mutex or condition variable in the c'tor and unlocks +it in the d'tor. It's easier and safer than manually locking and +unlocking since unlocking must usually be done no matter how a function +exits (including by unwinding due to an exception). +*/ class CLock { public: + //! Lock the mutex \c mutex CLock(const CMutex* mutex); + //! Lock the condition variable \c cv CLock(const CCondVarBase* cv); + //! Unlock the mutex or condition variable ~CLock(); private: diff --git a/mt/CMutex.h b/mt/CMutex.h index 2f6b9483..d3a87136 100644 --- a/mt/CMutex.h +++ b/mt/CMutex.h @@ -1,26 +1,59 @@ #ifndef CMUTEX_H #define CMUTEX_H -// recursive mutex class +//! Mutual exclusion +/*! +A non-recursive mutual exclusion object. Only one thread at a time can +hold a lock on a mutex. Any thread that attempts to lock a locked mutex +will block until the mutex is unlocked. At that time, if any threads are +blocked, exactly one waiting thread will acquire the lock and continue +running. A thread may not lock a mutex it already owns the lock on; if +it tries it will deadlock itself. +*/ class CMutex { public: - // copy c'tor is equivalent to default c'tor. it's here to - // allow copying of objects that have mutexes. CMutex(); + //! Equivalent to default c'tor + /*! + Copy c'tor doesn't copy anything. It just makes it possible to + copy objects that contain a mutex. + */ CMutex(const CMutex&); ~CMutex(); - // manipulators + //! @name manipulators + //@{ - // this has no effect. it's only here to allow assignment of - // objects that have mutexes. + //! Does nothing + /*! + This does nothing. It just makes it possible to assign objects + that contain a mutex. + */ CMutex& operator=(const CMutex&); - // accessors + //@} + //! @name accessors + //@{ + //! Lock the mutex + /*! + Locks the mutex, which must not have been previously locked by the + calling thread. This blocks if the mutex is already locked by another + thread. + + (cancellation point) + */ void lock() const; + + //! Unlock the mutex + /*! + Unlocks the mutex, which must have been previously locked by the + calling thread. + */ void unlock() const; + //@} + private: void init(); void fini(); diff --git a/mt/CThread.h b/mt/CThread.h index a6243707..d11626da 100644 --- a/mt/CThread.h +++ b/mt/CThread.h @@ -6,121 +6,219 @@ class IJob; class CThreadRep; +//! Thread handle +/*! +Creating a CThread creates a new context of execution (i.e. thread) that +runs simulatenously with the calling thread. A CThread is only a handle +to a thread; deleting a CThread does not cancel or destroy the thread it +refers to and multiple CThread objects can refer to the same thread. + +Threads can terminate themselves but cannot be forced to terminate by +other threads. However, other threads can signal a thread to terminate +itself by cancelling it. And a thread can wait (block) on another thread +to terminate. + +Most functions that can block for an arbitrary time are cancellation +points. A cancellation point is a function that can be interrupted by +a request to cancel the thread. Cancellation points are noted in the +documentation. +*/ // note -- do not derive from this class class CThread { public: - // create and start a new thread executing the job. - // the user data can be retrieved with getUserData(). - CThread(IJob* adopted, void* userData = 0); + //! Run \c adoptedJob in a new thread + /*! + Create and start a new thread executing the \c adoptedJob. The + user data can be retrieved with getUserData(). The new thread + takes ownership of \c adoptedJob and will delete it. + */ + CThread(IJob* adoptedJob, void* userData = 0); - // make a new thread object that refers to an existing thread. - // this does *not* start a new thread. + //! Duplicate a thread handle + /*! + Make a new thread object that refers to an existing thread. + This does \b not start a new thread. + */ CThread(const CThread&); - // release thread. this does not terminate the thread. a thread - // will keep running until the job completes or calls exit(). + //! Release a thread handle + /*! + Release a thread handle. This does not terminate the thread. A thread + will keep running until the job completes or calls exit() or allows + itself to be cancelled. + */ ~CThread(); - // manipulators + //! @name manipulators + //@{ - // assign thread. this has no effect on the threads. it simply - // makes this thread object refer to another thread. it does *not* - // start a new thread. + //! Assign thread handle + /*! + Assign a thread handle. This has no effect on the threads, it simply + makes this thread object refer to another thread. It does \b not + start a new thread. + */ CThread& operator=(const CThread&); - // initialize the thread library. this must be called before - // any other thread methods or creating a thread object. it - // is harmless to call init() multiple times. + //! Initialize the thread library + /*! + Initialize the thread library. This \b must be called before + any other thread methods or creating a thread object. It is + harmless to call init() multiple times. + */ static void init(); - // the calling thread sleeps for the given number of seconds. if - // timeout <= 0.0 then the call returns immediately. if timeout - // == 0.0 then the calling thread yields the CPU. - // (cancellation point) + //! Sleep + /*! + Blocks the calling thread for \c timeout seconds. If + \c timeout < 0.0 then the call returns immediately. If \c timeout + == 0.0 then the calling thread yields the CPU. + + (cancellation point) + */ static void sleep(double timeout); - // terminate the calling thread. this function does not return but - // the stack is unwound and automatic objects are destroyed, as if - // exit() threw an exception (which is, in fact, what it does). the - // argument is saved as the result returned by getResult(). if you - // have a catch(...) block then you should add the following before - // it to avoid catching the exit: catch(CThreadExit&) { throw; } + //! Terminate the calling thread + /*! + Terminate the calling thread. This function does not return but + the stack is unwound and automatic objects are destroyed, as if + exit() threw an exception (which is, in fact, what it does). The + argument is saved as the result returned by getResult(). If you + have \c catch(...) blocks then you should add the following before + each to avoid catching the exit: + \code + catch(CThreadExit&) { throw; } + \endcode + or add the \c RETHROW_XTHREAD macro to the \c catch(...) block. + */ static void exit(void*); - // enable/disable cancellation. default is enabled. this is not - // a cancellation point so if you enabled cancellation and want to - // allow immediate cancellation you need to call testCancel(). - // return value is the previous state. + //! Enable or disable cancellation + /*! + Enable or disable cancellation. The default is enabled. This is not + a cancellation point so if you just enabled cancellation and want to + allow immediate cancellation you need to call testCancel(). + Returns the previous state. + */ static bool enableCancel(bool); - // cancel the thread. cancel() never waits for the thread to - // terminate; it just posts the cancel and returns. a thread will - // terminate when it enters a cancellation point with cancellation - // enabled. if cancellation is disabled then the cancel is - // remembered but not acted on until the first call to a - // cancellation point after cancellation is enabled. - // - // a cancellation point is a function that can act on cancellation. - // a cancellation point does not return if there's a cancel pending. - // instead, it unwinds the stack and destroys automatic objects, as - // if cancel() threw an exception (which is, in fact, what it does). - // threads must take care to clean up and release any resources they - // may have, especially mutexes. they can catch (XThreadCancel) to - // do that then rethrow the exception or they can let it happen - // automatically by doing clean up in the d'tors of automatic - // objects. clients are strongly encouraged to do the latter. - // during cancellation, further cancel() calls are ignored (i.e. - // a thread cannot be interrupted by a cancel during cancellation). - // - // clients that catch (XThreadCancel) must always rethrow the - // exception. clients that catch(...) must either rethrow the - // exception or include a catch (XThreadCancel) handler that - // rethrows. + //! Cancel thread + /*! + Cancel the thread. cancel() never waits for the thread to + terminate; it just posts the cancel and returns. A thread will + terminate when it enters a cancellation point with cancellation + enabled. If cancellation is disabled then the cancel is + remembered but not acted on until the first call to a + cancellation point after cancellation is enabled. + + A cancellation point is a function that can act on cancellation. + A cancellation point does not return if there's a cancel pending. + Instead, it unwinds the stack and destroys automatic objects, as + if cancel() threw an exception (which is, in fact, what it does). + Threads must take care to unlock and clean up any resources they + may have, especially mutexes. They can \c catch(XThreadCancel) to + do that then rethrow the exception or they can let it happen + automatically by doing clean up in the d'tors of automatic + objects (like CLock). Clients are strongly encouraged to do the latter. + During cancellation, further cancel() calls are ignored (i.e. + a thread cannot be interrupted by a cancel during cancellation). + + Clients that \c catch(XThreadCancel) must always rethrow the + exception. Clients that \c catch(...) must either rethrow the + exception or include a \c catch(XThreadCancel) handler that + rethrows. The \c RETHROW_XTHREAD macro may be useful for that. + */ void cancel(); - // change the priority of the thread. normal priority is 0, 1 is - // the next lower, etc. -1 is the next higher, etc. but boosting - // the priority may not be available. + //! Change thread priority + /*! + Change the priority of the thread. Normal priority is 0, 1 is + the next lower, etc. -1 is the next higher, etc. but boosting + the priority may not be permitted and will be silenty ignored. + */ void setPriority(int n); - // accessors + //@} + //! @name accessors + //@{ - // return a thread object representing the calling thread + //! Get current thread's handle + /*! + Return a CThread object representing the calling thread. + */ static CThread getCurrentThread(); - // testCancel() does nothing but is a cancellation point. call - // this to make a function itself a cancellation point. - // (cancellation point) + //! Test for cancellation + /*! + testCancel() does nothing but is a cancellation point. Call + this to make a function itself a cancellation point. If the + thread was cancelled and cancellation is enabled this will + cause the thread to unwind the stack and terminate. + + (cancellation point) + */ static void testCancel(); - // get the user data passed to the constructor for this thread. + //! Get the thread user data + /*! + Gets the user data passed to the c'tor that created this thread. + */ void* getUserData(); - // waits for the thread to terminate (by exit() or cancel() or - // by returning from the thread job). returns immediately if - // the thread has already terminated. returns immediately with - // false if called by a thread on itself. returns false on - // timeout (or error) and true on success. - // (cancellation point) + //! Wait for thread to terminate + /*! + Waits for the thread to terminate (by exit() or cancel() or + by returning from the thread job) for up to \c timeout seconds, + returning true if the thread terminated and false otherwise. + This returns immediately with false if called by a thread on + itself and immediately with true if the thread has already + terminated. This will wait forever if \c timeout < 0.0. + + (cancellation point) + */ bool wait(double timeout = -1.0) const; #if WINDOWS_LIKE - // wait for a message in the queue. returns true if a message - // is available. - // (cancellation point) + //! Wait for an event (win32) + /*! + Wait for the message queue to contain a message for up to \c timeout + seconds. This returns immediately if any message is available + (including messages that were already in the queue during the last + call to \c GetMessage() or \c PeekMessage() or waitForEvent(). + Returns true iff a message is available. This will wait forever + if \c timeout < 0.0. + + This method is available under win32 only. + + (cancellation point) + */ static bool waitForEvent(double timeout = -1.0); #endif - // get the exit result. does an implicit wait(). returns NULL - // immediately if called by a thread on itself. returns NULL for - // threads that were cancelled. - // (cancellation point) + //! Get the exit result + /*! + Returns the exit result. This does an implicit wait(). It returns + NULL immediately if called by a thread on itself or on a thread that + was cancelled. + + (cancellation point) + */ void* getResult() const; - // compare threads for (in)equality + //! Compare thread handles + /*! + Returns true if two CThread objects refer to the same thread. + */ bool operator==(const CThread&) const; + + //! Compare thread handles + /*! + Returns true if two CThread objects do not refer to the same thread. + */ bool operator!=(const CThread&) const; + //@} + private: CThread(CThreadRep*); @@ -128,7 +226,11 @@ private: CThreadRep* m_rep; }; -// disables cancellation in the c'tor and enables it in the d'tor. +//! Disable cancellation utility +/*! +This class disables cancellation for the current thread in the c'tor +and enables it in the d'tor. +*/ class CThreadMaskCancel { public: CThreadMaskCancel(); diff --git a/mt/CThreadRep.h b/mt/CThreadRep.h index 8869492c..4177f50a 100644 --- a/mt/CThreadRep.h +++ b/mt/CThreadRep.h @@ -13,6 +13,7 @@ class CMutex; class IJob; +//! Internal thread class; do not use directly class CThreadRep { public: CThreadRep(IJob*, void* userData); diff --git a/mt/CTimerThread.h b/mt/CTimerThread.h index 5605fadc..722ecd21 100644 --- a/mt/CTimerThread.h +++ b/mt/CTimerThread.h @@ -3,12 +3,21 @@ class CThread; +//! A timer thread +/*! +An object of this class cancels the thread that called the c'tor unless +the object is destroyed before a given timeout. +*/ class CTimerThread { public: - // cancels the calling thread after timeout seconds unless destroyed - // before then. if timeout is less than zero then it never times - // out and is a no-op. + //! Cancel calling thread after \c timeout seconds + /*! + Cancels the calling thread after \c timeout seconds unless destroyed + before then. If \c timeout is less than zero then it never times + out and this is a no-op. + */ CTimerThread(double timeout); + //! Cancel the timer thread ~CTimerThread(); private: diff --git a/mt/XThread.h b/mt/XThread.h index 18c22f09..3a5e59e1 100644 --- a/mt/XThread.h +++ b/mt/XThread.h @@ -1,14 +1,18 @@ #ifndef XTHREAD_H #define XTHREAD_H -// generic thread exception +//! Generic thread exception class XThread { }; -// thrown by CThread::Exit() to exit a thread. clients of CThread -// must not throw this type but must rethrow it if caught (by -// XThreadExit, XThread, or ...). +//! Thread exception to exit +/*! +Thrown by CThread::exit() to exit a thread. Clients of CThread +must not throw this type but must rethrow it if caught (by +XThreadExit, XThread, or ...). +*/ class XThreadExit : public XThread { public: + //! \c result is the result of the thread XThreadExit(void* result) : m_result(result) { } ~XThreadExit() { } @@ -16,13 +20,19 @@ public: void* m_result; }; -// thrown to cancel a thread. clients must not throw this type, but -// must rethrow it if caught (by XThreadCancel, XThread, or ...). +//! Thread exception to cancel +/*! +Thrown to cancel a thread. Clients must not throw this type, but +must rethrow it if caught (by XThreadCancel, XThread, or ...). +*/ class XThreadCancel : public XThread { }; -// convenience macro to rethrow an XThread exception but ignore other -// exceptions. put this in your catch (...) handler after necessary -// cleanup but before leaving or returning from the handler. +/*! +\def RETHROW_XTHREAD +Convenience macro to rethrow an XThread exception but ignore other +exceptions. Put this in your catch (...) handler after necessary +cleanup but before leaving or returning from the handler. +*/ #define RETHROW_XTHREAD \ try { throw; } catch (XThread&) { throw; } catch (...) { }