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.
#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4)))
template<typename T> struct AIReadAccessConst;
template<typename T> struct AIReadAccess;
template<typename T> struct AIWriteAccess;
template<typename T, typename RWLOCK> struct AIReadAccessConst;
template<typename T, typename RWLOCK> struct AIReadAccess;
template<typename T, typename RWLOCK> struct AIWriteAccess;
template<typename T, typename MUTEX> struct AIAccessConst;
template<typename T, typename MUTEX> struct AIAccess;
template<typename T> struct AISTAccessConst;
@@ -225,17 +225,17 @@ protected:
* </code>
*
*/
template<typename T>
template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafe : public AIThreadSafeBits<T>
{
protected:
// Only these may access the object (through ptr()).
friend struct AIReadAccessConst<T>;
friend struct AIReadAccess<T>;
friend struct AIWriteAccess<T>;
friend struct AIReadAccessConst<T, RWLOCK>;
friend struct AIReadAccess<T, RWLOCK>;
friend struct AIWriteAccess<T, RWLOCK>;
// Locking control.
AIRWLock mRWLock;
RWLOCK mRWLock;
// For use by AIThreadSafeDC
AIThreadSafe(void) { }
@@ -310,20 +310,20 @@ public:
*
* which is not possible with AITHREADSAFE.
*/
template<typename T>
class AIThreadSafeDC : public AIThreadSafe<T>
template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafeDC : public AIThreadSafe<T, RWLOCK>
{
public:
// 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.
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.
*/
template<typename T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccessConst
{
//! Internal enum for the lock-type of the AI*Access object.
@@ -336,8 +336,8 @@ struct AIReadAccessConst
};
//! Construct a AIReadAccessConst from a constant AIThreadSafe.
AIReadAccessConst(AIThreadSafe<T> const& wrapper, bool high_priority = false)
: mWrapper(const_cast<AIThreadSafe<T>&>(wrapper)),
AIReadAccessConst(AIThreadSafe<T, RWLOCK> const& wrapper, bool high_priority = false)
: mWrapper(const_cast<AIThreadSafe<T, RWLOCK>&>(wrapper)),
mState(readlocked)
#if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false)
@@ -369,14 +369,14 @@ struct AIReadAccessConst
protected:
//! Constructor used by AIReadAccess.
AIReadAccessConst(AIThreadSafe<T>& wrapper, state_type state)
AIReadAccessConst(AIThreadSafe<T, RWLOCK>& wrapper, state_type state)
: mWrapper(wrapper), mState(state)
#if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false)
#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.
#if AI_NEED_ACCESS_CC
@@ -393,39 +393,39 @@ private:
/**
* @brief Read lock object and provide read access, with possible promotion to write access.
*/
template<typename T>
struct AIReadAccess : public AIReadAccessConst<T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccess : public AIReadAccessConst<T, RWLOCK>
{
typedef typename AIReadAccessConst<T>::state_type state_type;
using AIReadAccessConst<T>::readlocked;
typedef typename AIReadAccessConst<T, RWLOCK>::state_type state_type;
using AIReadAccessConst<T, RWLOCK>::readlocked;
//! 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:
//! 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.
*/
template<typename T>
struct AIWriteAccess : public AIReadAccess<T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIWriteAccess : public AIReadAccess<T, RWLOCK>
{
using AIReadAccessConst<T>::readlocked;
using AIReadAccessConst<T>::read2writelocked;
using AIReadAccessConst<T>::writelocked;
using AIReadAccessConst<T>::write2writelocked;
using AIReadAccessConst<T, RWLOCK>::readlocked;
using AIReadAccessConst<T, RWLOCK>::read2writelocked;
using AIReadAccessConst<T, RWLOCK>::writelocked;
using AIReadAccessConst<T, RWLOCK>::write2writelocked;
//! 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.
explicit AIWriteAccess(AIReadAccess<T>& access)
: AIReadAccess<T>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
explicit AIWriteAccess(AIReadAccess<T, RWLOCK>& access)
: AIReadAccess<T, RWLOCK>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
{
if (this->mState == read2writelocked)
{