Added doxygen comments for all relevant headers in mt.

This commit is contained in:
crs 2002-07-28 13:34:19 +00:00
parent 7a461855eb
commit 24d54fca53
7 changed files with 364 additions and 124 deletions

View File

@ -6,44 +6,97 @@
class CStopwatch; 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 { class CCondVarBase {
public: 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(CMutex* mutex);
~CCondVarBase(); ~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; void lock() const;
//! Unlock the condition variable's mutex
void unlock() const; void unlock() const;
// signal the condition. Signal() wakes one waiting thread. //! Signal the condition variable
// Broadcast() wakes all waiting threads. /*!
Wake up one waiting thread, if there are any. Which thread gets
woken is undefined.
*/
void signal(); void signal();
//! Signal the condition variable
/*!
Wake up all waiting threads, if any.
*/
void broadcast(); void broadcast();
// accessors //@}
//! @name accessors
//@{
// wait on the condition. if timeout < 0 then wait until signalled, //! Wait on the condition variable
// otherwise up to timeout seconds or until signalled, whichever /*!
// comes first. since clients normally wait on condition variables Wait on the condition variable. If \c timeout < 0 then wait until
// in a loop, clients can provide a CStopwatch that acts as the signalled, otherwise up to \c timeout seconds or until signalled,
// timeout clock. using it, clients don't have to recalculate the whichever comes first. Returns true if the object was signalled
// timeout on each iteration. passing a stopwatch with a negative during the wait, false otherwise.
// timeout is pointless but permitted.
// The proper way to wait for a condition is:
// returns true if the object was signalled during the wait, false \code
// otherwise. cv.lock();
// while (cv-expr) {
// (cancellation point) 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(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; CMutex* getMutex() const;
//@}
private: private:
void init(); void init();
void fini(); void fini();
@ -63,27 +116,49 @@ private:
#endif #endif
}; };
//! Condition variable
/*!
A condition variable with storage for type \c T.
*/
template <class T> template <class T>
class CCondVar : public CCondVarBase { class CCondVar : public CCondVarBase {
public: 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(const CCondVar&);
~CCondVar(); ~CCondVar();
// manipulators //! @name manipulators
//@{
// assigns the value of the variable //! Assigns the value of \c cv to this
CCondVar& operator=(const CCondVar&); /*!
Set the variable's value. The condition variable should be locked
before calling this method.
*/
CCondVar& operator=(const CCondVar& cv);
// assign the value //! Assigns \c value to this
CCondVar& operator=(const T&); /*!
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 //! Get the variable's value
// calling this method. /*!
Get the variable's value. The condition variable should be locked
before calling this method.
*/
operator const T&() const; operator const T&() const;
//@}
private: private:
T m_data; T m_data;
}; };

View File

@ -4,10 +4,20 @@
class CMutex; class CMutex;
class CCondVarBase; 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 { class CLock {
public: public:
//! Lock the mutex \c mutex
CLock(const CMutex* mutex); CLock(const CMutex* mutex);
//! Lock the condition variable \c cv
CLock(const CCondVarBase* cv); CLock(const CCondVarBase* cv);
//! Unlock the mutex or condition variable
~CLock(); ~CLock();
private: private:

View File

@ -1,26 +1,59 @@
#ifndef CMUTEX_H #ifndef CMUTEX_H
#define 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 { class CMutex {
public: public:
// copy c'tor is equivalent to default c'tor. it's here to
// allow copying of objects that have mutexes.
CMutex(); 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(const CMutex&);
~CMutex(); ~CMutex();
// manipulators //! @name manipulators
//@{
// this has no effect. it's only here to allow assignment of //! Does nothing
// objects that have mutexes. /*!
This does nothing. It just makes it possible to assign objects
that contain a mutex.
*/
CMutex& operator=(const CMutex&); 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; void lock() const;
//! Unlock the mutex
/*!
Unlocks the mutex, which must have been previously locked by the
calling thread.
*/
void unlock() const; void unlock() const;
//@}
private: private:
void init(); void init();
void fini(); void fini();

View File

@ -6,121 +6,219 @@
class IJob; class IJob;
class CThreadRep; 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 // note -- do not derive from this class
class CThread { class CThread {
public: public:
// create and start a new thread executing the job. //! Run \c adoptedJob in a new thread
// the user data can be retrieved with getUserData(). /*!
CThread(IJob* adopted, void* userData = 0); 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. //! Duplicate a thread handle
// this does *not* start a new thread. /*!
Make a new thread object that refers to an existing thread.
This does \b not start a new thread.
*/
CThread(const CThread&); CThread(const CThread&);
// release thread. this does not terminate the thread. a thread //! Release a thread handle
// will keep running until the job completes or calls exit(). /*!
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(); ~CThread();
// manipulators //! @name manipulators
//@{
// assign thread. this has no effect on the threads. it simply //! Assign thread handle
// makes this thread object refer to another thread. it does *not* /*!
// start a new thread. 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&); CThread& operator=(const CThread&);
// initialize the thread library. this must be called before //! Initialize the thread library
// any other thread methods or creating a thread object. it /*!
// is harmless to call init() multiple times. 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(); static void init();
// the calling thread sleeps for the given number of seconds. if //! Sleep
// timeout <= 0.0 then the call returns immediately. if timeout /*!
// == 0.0 then the calling thread yields the CPU. Blocks the calling thread for \c timeout seconds. If
// (cancellation point) \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); static void sleep(double timeout);
// terminate the calling thread. this function does not return but //! Terminate the calling thread
// the stack is unwound and automatic objects are destroyed, as if /*!
// exit() threw an exception (which is, in fact, what it does). the Terminate the calling thread. This function does not return but
// argument is saved as the result returned by getResult(). if you the stack is unwound and automatic objects are destroyed, as if
// have a catch(...) block then you should add the following before exit() threw an exception (which is, in fact, what it does). The
// it to avoid catching the exit: catch(CThreadExit&) { throw; } 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*); static void exit(void*);
// enable/disable cancellation. default is enabled. this is not //! Enable or disable cancellation
// a cancellation point so if you enabled cancellation and want to /*!
// allow immediate cancellation you need to call testCancel(). Enable or disable cancellation. The default is enabled. This is not
// return value is the previous state. 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); static bool enableCancel(bool);
// cancel the thread. cancel() never waits for the thread to //! Cancel thread
// terminate; it just posts the cancel and returns. a thread will /*!
// terminate when it enters a cancellation point with cancellation Cancel the thread. cancel() never waits for the thread to
// enabled. if cancellation is disabled then the cancel is terminate; it just posts the cancel and returns. A thread will
// remembered but not acted on until the first call to a terminate when it enters a cancellation point with cancellation
// cancellation point after cancellation is enabled. enabled. If cancellation is disabled then the cancel is
// remembered but not acted on until the first call to a
// a cancellation point is a function that can act on cancellation. cancellation point after cancellation is enabled.
// a cancellation point does not return if there's a cancel pending.
// instead, it unwinds the stack and destroys automatic objects, as A cancellation point is a function that can act on cancellation.
// if cancel() threw an exception (which is, in fact, what it does). A cancellation point does not return if there's a cancel pending.
// threads must take care to clean up and release any resources they Instead, it unwinds the stack and destroys automatic objects, as
// may have, especially mutexes. they can catch (XThreadCancel) to if cancel() threw an exception (which is, in fact, what it does).
// do that then rethrow the exception or they can let it happen Threads must take care to unlock and clean up any resources they
// automatically by doing clean up in the d'tors of automatic may have, especially mutexes. They can \c catch(XThreadCancel) to
// objects. clients are strongly encouraged to do the latter. do that then rethrow the exception or they can let it happen
// during cancellation, further cancel() calls are ignored (i.e. automatically by doing clean up in the d'tors of automatic
// a thread cannot be interrupted by a cancel during cancellation). objects (like CLock). Clients are strongly encouraged to do the latter.
// During cancellation, further cancel() calls are ignored (i.e.
// clients that catch (XThreadCancel) must always rethrow the a thread cannot be interrupted by a cancel during cancellation).
// exception. clients that catch(...) must either rethrow the
// exception or include a catch (XThreadCancel) handler that Clients that \c catch(XThreadCancel) must always rethrow the
// rethrows. 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(); void cancel();
// change the priority of the thread. normal priority is 0, 1 is //! Change thread priority
// the next lower, etc. -1 is the next higher, etc. but boosting /*!
// the priority may not be available. 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); 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(); static CThread getCurrentThread();
// testCancel() does nothing but is a cancellation point. call //! Test for cancellation
// this to make a function itself a cancellation point. /*!
// (cancellation point) 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(); 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(); void* getUserData();
// waits for the thread to terminate (by exit() or cancel() or //! Wait for thread to terminate
// by returning from the thread job). returns immediately if /*!
// the thread has already terminated. returns immediately with Waits for the thread to terminate (by exit() or cancel() or
// false if called by a thread on itself. returns false on by returning from the thread job) for up to \c timeout seconds,
// timeout (or error) and true on success. returning true if the thread terminated and false otherwise.
// (cancellation point) 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; bool wait(double timeout = -1.0) const;
#if WINDOWS_LIKE #if WINDOWS_LIKE
// wait for a message in the queue. returns true if a message //! Wait for an event (win32)
// is available. /*!
// (cancellation point) 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); static bool waitForEvent(double timeout = -1.0);
#endif #endif
// get the exit result. does an implicit wait(). returns NULL //! Get the exit result
// immediately if called by a thread on itself. returns NULL for /*!
// threads that were cancelled. Returns the exit result. This does an implicit wait(). It returns
// (cancellation point) NULL immediately if called by a thread on itself or on a thread that
was cancelled.
(cancellation point)
*/
void* getResult() const; 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; 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; bool operator!=(const CThread&) const;
//@}
private: private:
CThread(CThreadRep*); CThread(CThreadRep*);
@ -128,7 +226,11 @@ private:
CThreadRep* m_rep; 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 { class CThreadMaskCancel {
public: public:
CThreadMaskCancel(); CThreadMaskCancel();

View File

@ -13,6 +13,7 @@
class CMutex; class CMutex;
class IJob; class IJob;
//! Internal thread class; do not use directly
class CThreadRep { class CThreadRep {
public: public:
CThreadRep(IJob*, void* userData); CThreadRep(IJob*, void* userData);

View File

@ -3,12 +3,21 @@
class CThread; 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 { class CTimerThread {
public: public:
// cancels the calling thread after timeout seconds unless destroyed //! Cancel calling thread after \c timeout seconds
// before then. if timeout is less than zero then it never times /*!
// out and is a no-op. 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); CTimerThread(double timeout);
//! Cancel the timer thread
~CTimerThread(); ~CTimerThread();
private: private:

View File

@ -1,14 +1,18 @@
#ifndef XTHREAD_H #ifndef XTHREAD_H
#define XTHREAD_H #define XTHREAD_H
// generic thread exception //! Generic thread exception
class XThread { }; class XThread { };
// thrown by CThread::Exit() to exit a thread. clients of CThread //! Thread exception to exit
// must not throw this type but must rethrow it if caught (by /*!
// XThreadExit, XThread, or ...). 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 { class XThreadExit : public XThread {
public: public:
//! \c result is the result of the thread
XThreadExit(void* result) : m_result(result) { } XThreadExit(void* result) : m_result(result) { }
~XThreadExit() { } ~XThreadExit() { }
@ -16,13 +20,19 @@ public:
void* m_result; void* m_result;
}; };
// thrown to cancel a thread. clients must not throw this type, but //! Thread exception to cancel
// must rethrow it if caught (by XThreadCancel, XThread, or ...). /*!
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 { }; class XThreadCancel : public XThread { };
// convenience macro to rethrow an XThread exception but ignore other /*!
// exceptions. put this in your catch (...) handler after necessary \def RETHROW_XTHREAD
// cleanup but before leaving or returning from the handler. 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 \ #define RETHROW_XTHREAD \
try { throw; } catch (XThread&) { throw; } catch (...) { } try { throw; } catch (XThread&) { throw; } catch (...) { }