2001-10-06 18:13:28 +04:00
|
|
|
#ifndef CCONDVAR_H
|
|
|
|
#define CCONDVAR_H
|
|
|
|
|
|
|
|
#include "CMutex.h"
|
|
|
|
#include "BasicTypes.h"
|
|
|
|
|
|
|
|
class CStopwatch;
|
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! 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.
|
|
|
|
*/
|
2001-10-06 18:13:28 +04:00
|
|
|
class CCondVarBase {
|
2002-04-29 18:40:01 +04:00
|
|
|
public:
|
2002-07-28 17:34:19 +04:00
|
|
|
/*!
|
|
|
|
\c mutex must not be NULL. All condition variables have an
|
|
|
|
associated mutex. The mutex needn't be unique to one condition
|
|
|
|
variable.
|
|
|
|
*/
|
2001-10-06 18:13:28 +04:00
|
|
|
CCondVarBase(CMutex* mutex);
|
|
|
|
~CCondVarBase();
|
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! @name manipulators
|
|
|
|
//@{
|
2001-10-06 18:13:28 +04:00
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! 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.
|
|
|
|
*/
|
2001-10-14 20:58:01 +04:00
|
|
|
void lock() const;
|
2002-07-28 17:34:19 +04:00
|
|
|
|
|
|
|
//! Unlock the condition variable's mutex
|
2001-10-14 20:58:01 +04:00
|
|
|
void unlock() const;
|
2001-10-06 18:13:28 +04:00
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! Signal the condition variable
|
|
|
|
/*!
|
|
|
|
Wake up one waiting thread, if there are any. Which thread gets
|
|
|
|
woken is undefined.
|
|
|
|
*/
|
2001-10-14 20:58:01 +04:00
|
|
|
void signal();
|
2002-07-28 17:34:19 +04:00
|
|
|
|
|
|
|
//! Signal the condition variable
|
|
|
|
/*!
|
|
|
|
Wake up all waiting threads, if any.
|
|
|
|
*/
|
2001-10-14 20:58:01 +04:00
|
|
|
void broadcast();
|
2001-10-06 18:13:28 +04:00
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//@}
|
|
|
|
//! @name accessors
|
|
|
|
//@{
|
|
|
|
|
|
|
|
//! 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)
|
|
|
|
*/
|
2001-10-06 18:13:28 +04:00
|
|
|
bool wait(double timeout = -1.0) const;
|
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! 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.
|
|
|
|
*/
|
2001-10-14 20:58:01 +04:00
|
|
|
CMutex* getMutex() const;
|
2001-10-06 18:13:28 +04:00
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//@}
|
|
|
|
|
2002-04-29 18:40:01 +04:00
|
|
|
private:
|
2001-10-06 18:13:28 +04:00
|
|
|
void init();
|
|
|
|
void fini();
|
|
|
|
|
|
|
|
// not implemented
|
|
|
|
CCondVarBase(const CCondVarBase&);
|
|
|
|
CCondVarBase& operator=(const CCondVarBase&);
|
|
|
|
|
2002-04-29 18:40:01 +04:00
|
|
|
private:
|
2001-10-06 18:13:28 +04:00
|
|
|
CMutex* m_mutex;
|
|
|
|
void* m_cond;
|
|
|
|
|
2002-06-19 15:23:49 +04:00
|
|
|
#if WINDOWS_LIKE
|
2001-10-06 18:13:28 +04:00
|
|
|
enum { kSignal, kBroadcast };
|
|
|
|
mutable UInt32 m_waitCount;
|
|
|
|
CMutex m_waitCountMutex;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! Condition variable
|
|
|
|
/*!
|
|
|
|
A condition variable with storage for type \c T.
|
|
|
|
*/
|
2001-10-06 18:13:28 +04:00
|
|
|
template <class T>
|
|
|
|
class CCondVar : public CCondVarBase {
|
2002-04-29 18:40:01 +04:00
|
|
|
public:
|
2002-07-28 17:34:19 +04:00
|
|
|
//! Initialize using \c value
|
|
|
|
CCondVar(CMutex* mutex, const T& value);
|
|
|
|
//! Initialize using another condition variable's value
|
2001-10-06 18:13:28 +04:00
|
|
|
CCondVar(const CCondVar&);
|
|
|
|
~CCondVar();
|
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//! @name manipulators
|
|
|
|
//@{
|
|
|
|
|
|
|
|
//! 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);
|
|
|
|
|
|
|
|
//! 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);
|
|
|
|
|
|
|
|
//@}
|
|
|
|
//! @name accessors
|
|
|
|
//@{
|
|
|
|
|
|
|
|
//! Get the variable's value
|
|
|
|
/*!
|
|
|
|
Get the variable's value. The condition variable should be locked
|
|
|
|
before calling this method.
|
|
|
|
*/
|
2001-10-14 20:58:01 +04:00
|
|
|
operator const T&() const;
|
2001-10-06 18:13:28 +04:00
|
|
|
|
2002-07-28 17:34:19 +04:00
|
|
|
//@}
|
|
|
|
|
2002-04-29 18:40:01 +04:00
|
|
|
private:
|
2001-10-06 18:13:28 +04:00
|
|
|
T m_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
2002-06-11 02:06:45 +04:00
|
|
|
CCondVar<T>::CCondVar(
|
|
|
|
CMutex* mutex,
|
|
|
|
const T& data) :
|
|
|
|
CCondVarBase(mutex),
|
|
|
|
m_data(data)
|
2001-10-06 18:13:28 +04:00
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
2002-06-11 02:06:45 +04:00
|
|
|
CCondVar<T>::CCondVar(
|
|
|
|
const CCondVar& cv) :
|
|
|
|
CCondVarBase(cv.getMutex()),
|
|
|
|
m_data(cv.m_data)
|
2001-10-06 18:13:28 +04:00
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
|
|
|
CCondVar<T>::~CCondVar()
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
2002-06-11 02:06:45 +04:00
|
|
|
CCondVar<T>&
|
|
|
|
CCondVar<T>::operator=(
|
|
|
|
const CCondVar<T>& cv)
|
2001-10-06 18:13:28 +04:00
|
|
|
{
|
|
|
|
m_data = cv.m_data;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
2002-06-11 02:06:45 +04:00
|
|
|
CCondVar<T>&
|
|
|
|
CCondVar<T>::operator=(
|
|
|
|
const T& data)
|
2001-10-06 18:13:28 +04:00
|
|
|
{
|
|
|
|
m_data = data;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
inline
|
2001-10-14 20:58:01 +04:00
|
|
|
CCondVar<T>::operator const T&() const
|
2001-10-06 18:13:28 +04:00
|
|
|
{
|
|
|
|
return m_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// force instantiation of these common types
|
|
|
|
template class CCondVar<bool>;
|
|
|
|
template class CCondVar<SInt32>;
|
|
|
|
|
|
|
|
#endif
|