eathread_rwmutex.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /////////////////////////////////////////////////////////////////////////////
  5. // Implements a lightweight mutex with multiple reads but single writer.
  6. // This allows for high performance systems whereby the consumers of data
  7. // are more common than the producers of data.
  8. /////////////////////////////////////////////////////////////////////////////
  9. #ifndef EATHREAD_EATHREAD_RWMUTEX_H
  10. #define EATHREAD_EATHREAD_RWMUTEX_H
  11. #include <EABase/eabase.h>
  12. #include <eathread/eathread.h>
  13. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  14. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  15. #endif
  16. /////////////////////////////////////////////////////////////////////////
  17. /// EARWMutexData
  18. ///
  19. /// This is used internally by class RWMutex.
  20. /// Todo: Consider moving this declaration into a platform-specific
  21. /// header file.
  22. ///
  23. #include <eathread/eathread_mutex.h>
  24. #include <eathread/eathread_condition.h>
  25. struct EATHREADLIB_API EARWMutexData
  26. {
  27. int mnReadWaiters;
  28. int mnWriteWaiters;
  29. int mnReaders;
  30. EA::Thread::ThreadId mThreadIdWriter;
  31. EA::Thread::Mutex mMutex;
  32. EA::Thread::Condition mReadCondition;
  33. EA::Thread::Condition mWriteCondition;
  34. EARWMutexData();
  35. private:
  36. // Prevent default generation of these functions by declaring but not defining them.
  37. EARWMutexData(const EARWMutexData& rhs); // copy constructor
  38. EARWMutexData& operator=(const EARWMutexData& rhs); // assignment operator
  39. };
  40. /////////////////////////////////////////////////////////////////////////
  41. namespace EA
  42. {
  43. namespace Thread
  44. {
  45. /// RWMutexParameters
  46. /// Specifies rwlock settings.
  47. struct EATHREADLIB_API RWMutexParameters
  48. {
  49. bool mbIntraProcess; /// True if the mutex is intra-process, else inter-process.
  50. char mName[16]; /// Mutex name, applicable only to platforms that recognize named synchronization objects.
  51. RWMutexParameters(bool bIntraProcess = true, const char* pName = NULL);
  52. };
  53. /// class RWMutex
  54. /// Implements a multiple reader / single writer mutex.
  55. /// This allows for significantly higher performance when data to be protected
  56. /// is read much more frequently than written. In this case, a waiting writer
  57. /// gets top priority and all new readers block after a waiter starts waiting.
  58. class EATHREADLIB_API RWMutex
  59. {
  60. public:
  61. enum Result
  62. {
  63. kResultError = -1,
  64. kResultTimeout = -2
  65. };
  66. enum LockType
  67. {
  68. kLockTypeNone = 0,
  69. kLockTypeRead = 1,
  70. kLockTypeWrite = 2
  71. };
  72. /// RWMutex
  73. /// For immediate default initialization, use no args.
  74. /// For custom immediate initialization, supply a first argument.
  75. /// For deferred initialization, use RWMutex(NULL, false) then later call Init.
  76. /// For deferred initialization of an array of objects, create an empty
  77. /// subclass whose default constructor chains back to RWMutex(NULL, false).
  78. RWMutex(const RWMutexParameters* pRWMutexParameters = NULL, bool bDefaultParameters = true);
  79. /// ~RWMutex
  80. /// Destroys an existing mutex. The mutex must not be locked by any thread,
  81. /// otherwise the resulting behaviour is undefined.
  82. ~RWMutex();
  83. /// Init
  84. /// Initializes the mutex if not done so in the constructor.
  85. /// This should only be called in the case that this class was constructed
  86. /// with RWMutex(NULL, false).
  87. bool Init(const RWMutexParameters* pRWMutexParameters);
  88. /// Lock
  89. /// Returns the new lock count for the given lock type.
  90. ///
  91. /// Note that the timeout is specified in absolute time and not relative time.
  92. ///
  93. /// Note also that due to the way thread scheduling works -- particularly in a
  94. /// time-sliced threading environment -- that the timeout value is a hint and
  95. /// the actual amount of time passed before the timeout occurs may be significantly
  96. /// more or less than the specified timeout time.
  97. ///
  98. int Lock(LockType lockType, const ThreadTime& timeoutAbsolute = EA::Thread::kTimeoutNone);
  99. /// Unlock
  100. /// Unlocks the mutex. The mutex must already be locked by the
  101. /// calling thread. Otherwise the behaviour is not defined.
  102. /// Return value is the lock count value immediately upon unlock
  103. /// or is one of enum Result.
  104. int Unlock();
  105. /// GetLockCount
  106. int GetLockCount(LockType lockType);
  107. /// GetPlatformData
  108. /// Returns the platform-specific data handle for debugging uses or
  109. /// other cases whereby special (and non-portable) uses are required.
  110. void* GetPlatformData()
  111. { return &mRWMutexData; }
  112. protected:
  113. EARWMutexData mRWMutexData;
  114. private:
  115. // Objects of this class are not copyable.
  116. RWMutex(const RWMutex&){}
  117. RWMutex& operator=(const RWMutex&){ return *this; }
  118. };
  119. /// RWMutexFactory
  120. ///
  121. /// Implements a factory-based creation and destruction mechanism for class RWMutex.
  122. /// A primary use of this would be to allow the RWMutex implementation to reside in
  123. /// a private library while users of the class interact only with the interface
  124. /// header and the factory. The factory provides conventional create/destroy
  125. /// semantics which use global operator new, but also provides manual construction/
  126. /// destruction semantics so that the user can provide for memory allocation
  127. /// and deallocation.
  128. class EATHREADLIB_API RWMutexFactory
  129. {
  130. public:
  131. static RWMutex* CreateRWMutex(); // Internally implemented as: return new RWMutex;
  132. static void DestroyRWMutex(RWMutex* pRWMutex); // Internally implemented as: delete pRWMutex;
  133. static size_t GetRWMutexSize(); // Internally implemented as: return sizeof(RWMutex);
  134. static RWMutex* ConstructRWMutex(void* pMemory); // Internally implemented as: return new(pMemory) RWMutex;
  135. static void DestructRWMutex(RWMutex* pRWMutex); // Internally implemented as: pRWMutex->~RWMutex();
  136. };
  137. } // namespace Thread
  138. } // namespace EA
  139. namespace EA
  140. {
  141. namespace Thread
  142. {
  143. /// class AutoRWMutex
  144. /// An AutoRWMutex locks the RWMutex in its constructor and
  145. /// unlocks the AutoRWMutex in its destructor (when it goes out of scope).
  146. class AutoRWMutex
  147. {
  148. public:
  149. AutoRWMutex(RWMutex& mutex, RWMutex::LockType lockType)
  150. : mMutex(mutex)
  151. { mMutex.Lock(lockType); }
  152. ~AutoRWMutex()
  153. { mMutex.Unlock(); }
  154. protected:
  155. RWMutex& mMutex;
  156. // Prevent copying by default, as copying is dangerous.
  157. AutoRWMutex(const AutoRWMutex&);
  158. const AutoRWMutex& operator=(const AutoRWMutex&);
  159. };
  160. } // namespace Thread
  161. } // namespace EA
  162. #endif // EATHREAD_EATHREAD_RWMUTEX_H