Make the type of the read/write lock of AIThreadSafe a template parameter.

This allows passing a different type than the default AIRWLock for
debugging purposes.

The signature of the class used for RWLOCK should be:

struct RWLock {
  // Default constructor.
  RWLock(void);

  // Block until it's safe to read the data.
  // high_priority is a hint that granting this thread the read lock is more important than granting another thread a write lock.
  void rdlock(bool high_priority = false);
  // Release the obtained read lock.
  void rdunlock();
  // Block until it's safe to write to the data.
  void wrlock();
  // Release the obtained write lock.
  void wrunlock();
  // Convert the obtained write lock into a read lock.
  void wr2rdlock();
  // Block until it is possible to convert the obtained read lock into a write lock.
  void rd2wrlock();

  // Return true when a read or write is obtained and subsequent calls to release the lock are expected.
  bool isLocked() const;
};
This commit is contained in:
Aleric Inglewood
2013-02-04 22:41:46 +01:00
parent 38d1525092
commit adf4c9a0ce

View File

@@ -106,9 +106,9 @@
// on a compiler that doesn't need this hack. // on a compiler that doesn't need this hack.
#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4))) #define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4)))
template<typename T> struct AIReadAccessConst; template<typename T, typename RWLOCK> struct AIReadAccessConst;
template<typename T> struct AIReadAccess; template<typename T, typename RWLOCK> struct AIReadAccess;
template<typename T> struct AIWriteAccess; template<typename T, typename RWLOCK> struct AIWriteAccess;
template<typename T, typename MUTEX> struct AIAccessConst; template<typename T, typename MUTEX> struct AIAccessConst;
template<typename T, typename MUTEX> struct AIAccess; template<typename T, typename MUTEX> struct AIAccess;
template<typename T> struct AISTAccessConst; template<typename T> struct AISTAccessConst;
@@ -225,17 +225,17 @@ protected:
* </code> * </code>
* *
*/ */
template<typename T> template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafe : public AIThreadSafeBits<T> class AIThreadSafe : public AIThreadSafeBits<T>
{ {
protected: protected:
// Only these may access the object (through ptr()). // Only these may access the object (through ptr()).
friend struct AIReadAccessConst<T>; friend struct AIReadAccessConst<T, RWLOCK>;
friend struct AIReadAccess<T>; friend struct AIReadAccess<T, RWLOCK>;
friend struct AIWriteAccess<T>; friend struct AIWriteAccess<T, RWLOCK>;
// Locking control. // Locking control.
AIRWLock mRWLock; RWLOCK mRWLock;
// For use by AIThreadSafeDC // For use by AIThreadSafeDC
AIThreadSafe(void) { } AIThreadSafe(void) { }
@@ -310,20 +310,20 @@ public:
* *
* which is not possible with AITHREADSAFE. * which is not possible with AITHREADSAFE.
*/ */
template<typename T> template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafeDC : public AIThreadSafe<T> class AIThreadSafeDC : public AIThreadSafe<T, RWLOCK>
{ {
public: public:
// Construct a wrapper around a default constructed object. // Construct a wrapper around a default constructed object.
AIThreadSafeDC(void) { new (AIThreadSafe<T>::ptr()) T; } AIThreadSafeDC(void) { new (AIThreadSafe<T, RWLOCK>::ptr()) T; }
// Allow an arbitrary parameter to be passed for construction. // Allow an arbitrary parameter to be passed for construction.
template<typename T2> AIThreadSafeDC(T2 const& val) { new (AIThreadSafe<T>::ptr()) T(val); } template<typename T2> AIThreadSafeDC(T2 const& val) { new (AIThreadSafe<T, RWLOCK>::ptr()) T(val); }
}; };
/** /**
* @brief Read lock object and provide read access. * @brief Read lock object and provide read access.
*/ */
template<typename T> template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccessConst struct AIReadAccessConst
{ {
//! Internal enum for the lock-type of the AI*Access object. //! Internal enum for the lock-type of the AI*Access object.
@@ -336,8 +336,8 @@ struct AIReadAccessConst
}; };
//! Construct a AIReadAccessConst from a constant AIThreadSafe. //! Construct a AIReadAccessConst from a constant AIThreadSafe.
AIReadAccessConst(AIThreadSafe<T> const& wrapper, bool high_priority = false) AIReadAccessConst(AIThreadSafe<T, RWLOCK> const& wrapper, bool high_priority = false)
: mWrapper(const_cast<AIThreadSafe<T>&>(wrapper)), : mWrapper(const_cast<AIThreadSafe<T, RWLOCK>&>(wrapper)),
mState(readlocked) mState(readlocked)
#if AI_NEED_ACCESS_CC #if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false) , mIsCopyConstructed(false)
@@ -369,14 +369,14 @@ struct AIReadAccessConst
protected: protected:
//! Constructor used by AIReadAccess. //! Constructor used by AIReadAccess.
AIReadAccessConst(AIThreadSafe<T>& wrapper, state_type state) AIReadAccessConst(AIThreadSafe<T, RWLOCK>& wrapper, state_type state)
: mWrapper(wrapper), mState(state) : mWrapper(wrapper), mState(state)
#if AI_NEED_ACCESS_CC #if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false) , mIsCopyConstructed(false)
#endif #endif
{ } { }
AIThreadSafe<T>& mWrapper; //!< Reference to the object that we provide access to. AIThreadSafe<T, RWLOCK>& mWrapper; //!< Reference to the object that we provide access to.
state_type const mState; //!< The lock state that mWrapper is in. state_type const mState; //!< The lock state that mWrapper is in.
#if AI_NEED_ACCESS_CC #if AI_NEED_ACCESS_CC
@@ -393,39 +393,39 @@ private:
/** /**
* @brief Read lock object and provide read access, with possible promotion to write access. * @brief Read lock object and provide read access, with possible promotion to write access.
*/ */
template<typename T> template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccess : public AIReadAccessConst<T> struct AIReadAccess : public AIReadAccessConst<T, RWLOCK>
{ {
typedef typename AIReadAccessConst<T>::state_type state_type; typedef typename AIReadAccessConst<T, RWLOCK>::state_type state_type;
using AIReadAccessConst<T>::readlocked; using AIReadAccessConst<T, RWLOCK>::readlocked;
//! Construct a AIReadAccess from a non-constant AIThreadSafe. //! Construct a AIReadAccess from a non-constant AIThreadSafe.
AIReadAccess(AIThreadSafe<T>& wrapper, bool high_priority = false) : AIReadAccessConst<T>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); } AIReadAccess(AIThreadSafe<T, RWLOCK>& wrapper, bool high_priority = false) : AIReadAccessConst<T, RWLOCK>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); }
protected: protected:
//! Constructor used by AIWriteAccess. //! Constructor used by AIWriteAccess.
AIReadAccess(AIThreadSafe<T>& wrapper, state_type state) : AIReadAccessConst<T>(wrapper, state) { } AIReadAccess(AIThreadSafe<T, RWLOCK>& wrapper, state_type state) : AIReadAccessConst<T, RWLOCK>(wrapper, state) { }
friend struct AIWriteAccess<T>; friend struct AIWriteAccess<T, RWLOCK>;
}; };
/** /**
* @brief Write lock object and provide read/write access. * @brief Write lock object and provide read/write access.
*/ */
template<typename T> template<typename T, typename RWLOCK = AIRWLock>
struct AIWriteAccess : public AIReadAccess<T> struct AIWriteAccess : public AIReadAccess<T, RWLOCK>
{ {
using AIReadAccessConst<T>::readlocked; using AIReadAccessConst<T, RWLOCK>::readlocked;
using AIReadAccessConst<T>::read2writelocked; using AIReadAccessConst<T, RWLOCK>::read2writelocked;
using AIReadAccessConst<T>::writelocked; using AIReadAccessConst<T, RWLOCK>::writelocked;
using AIReadAccessConst<T>::write2writelocked; using AIReadAccessConst<T, RWLOCK>::write2writelocked;
//! Construct a AIWriteAccess from a non-constant AIThreadSafe. //! Construct a AIWriteAccess from a non-constant AIThreadSafe.
AIWriteAccess(AIThreadSafe<T>& wrapper) : AIReadAccess<T>(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();} AIWriteAccess(AIThreadSafe<T, RWLOCK>& wrapper) : AIReadAccess<T, RWLOCK>(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
//! Promote read access to write access. //! Promote read access to write access.
explicit AIWriteAccess(AIReadAccess<T>& access) explicit AIWriteAccess(AIReadAccess<T, RWLOCK>& access)
: AIReadAccess<T>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked) : AIReadAccess<T, RWLOCK>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
{ {
if (this->mState == read2writelocked) if (this->mState == read2writelocked)
{ {