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;
//! 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 T>
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;
};

View File

@ -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:

View File

@ -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();

View File

@ -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();

View File

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

View File

@ -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:

View File

@ -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 (...) { }