sync.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // ECOin - Copyright (c) - 2014/2022 - GPLv3 - epsylon@riseup.net (https://03c8.net)
  2. #ifndef ECOIN_SYNC_H
  3. #define ECOIN_SYNC_H
  4. #include <boost/thread/mutex.hpp>
  5. #include <boost/thread/recursive_mutex.hpp>
  6. #include <boost/thread/locks.hpp>
  7. #include <boost/thread/condition_variable.hpp>
  8. /** Wrapped boost mutex: supports recursive locking, but no waiting */
  9. typedef boost::recursive_mutex CCriticalSection;
  10. /** Wrapped boost mutex: supports waiting but not recursive locking */
  11. typedef boost::mutex CWaitableCriticalSection;
  12. #ifdef DEBUG_LOCKORDER
  13. void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
  14. void LeaveCritical();
  15. #else
  16. void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
  17. void static inline LeaveCritical() {}
  18. #endif
  19. #ifdef DEBUG_LOCKCONTENTION
  20. void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
  21. #endif
  22. /** Wrapper around boost::unique_lock<Mutex> */
  23. template<typename Mutex>
  24. class CMutexLock
  25. {
  26. private:
  27. boost::unique_lock<Mutex> lock;
  28. public:
  29. void Enter(const char* pszName, const char* pszFile, int nLine)
  30. {
  31. if (!lock.owns_lock())
  32. {
  33. EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
  34. #ifdef DEBUG_LOCKCONTENTION
  35. if (!lock.try_lock())
  36. {
  37. PrintLockContention(pszName, pszFile, nLine);
  38. #endif
  39. lock.lock();
  40. #ifdef DEBUG_LOCKCONTENTION
  41. }
  42. #endif
  43. }
  44. }
  45. void Leave()
  46. {
  47. if (lock.owns_lock())
  48. {
  49. lock.unlock();
  50. LeaveCritical();
  51. }
  52. }
  53. bool TryEnter(const char* pszName, const char* pszFile, int nLine)
  54. {
  55. if (!lock.owns_lock())
  56. {
  57. EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
  58. lock.try_lock();
  59. if (!lock.owns_lock())
  60. LeaveCritical();
  61. }
  62. return lock.owns_lock();
  63. }
  64. CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
  65. {
  66. if (fTry)
  67. TryEnter(pszName, pszFile, nLine);
  68. else
  69. Enter(pszName, pszFile, nLine);
  70. }
  71. ~CMutexLock()
  72. {
  73. if (lock.owns_lock())
  74. LeaveCritical();
  75. }
  76. operator bool()
  77. {
  78. return lock.owns_lock();
  79. }
  80. boost::unique_lock<Mutex> &GetLock()
  81. {
  82. return lock;
  83. }
  84. };
  85. typedef CMutexLock<CCriticalSection> CCriticalBlock;
  86. #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
  87. #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
  88. #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
  89. #define ENTER_CRITICAL_SECTION(cs) \
  90. { \
  91. EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
  92. (cs).lock(); \
  93. }
  94. #define LEAVE_CRITICAL_SECTION(cs) \
  95. { \
  96. (cs).unlock(); \
  97. LeaveCritical(); \
  98. }
  99. class CSemaphore
  100. {
  101. private:
  102. boost::condition_variable condition;
  103. boost::mutex mutex;
  104. int value;
  105. public:
  106. CSemaphore(int init) : value(init) {}
  107. void wait() {
  108. boost::unique_lock<boost::mutex> lock(mutex);
  109. while (value < 1) {
  110. condition.wait(lock);
  111. }
  112. value--;
  113. }
  114. bool try_wait() {
  115. boost::unique_lock<boost::mutex> lock(mutex);
  116. if (value < 1)
  117. return false;
  118. value--;
  119. return true;
  120. }
  121. void post() {
  122. {
  123. boost::unique_lock<boost::mutex> lock(mutex);
  124. value++;
  125. }
  126. condition.notify_one();
  127. }
  128. };
  129. /** RAII-style semaphore lock */
  130. class CSemaphoreGrant
  131. {
  132. private:
  133. CSemaphore *sem;
  134. bool fHaveGrant;
  135. public:
  136. void Acquire() {
  137. if (fHaveGrant)
  138. return;
  139. sem->wait();
  140. fHaveGrant = true;
  141. }
  142. void Release() {
  143. if (!fHaveGrant)
  144. return;
  145. sem->post();
  146. fHaveGrant = false;
  147. }
  148. bool TryAcquire() {
  149. if (!fHaveGrant && sem->try_wait())
  150. fHaveGrant = true;
  151. return fHaveGrant;
  152. }
  153. void MoveTo(CSemaphoreGrant &grant) {
  154. grant.Release();
  155. grant.sem = sem;
  156. grant.fHaveGrant = fHaveGrant;
  157. sem = NULL;
  158. fHaveGrant = false;
  159. }
  160. CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
  161. CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
  162. if (fTry)
  163. TryAcquire();
  164. else
  165. Acquire();
  166. }
  167. ~CSemaphoreGrant() {
  168. Release();
  169. }
  170. operator bool() {
  171. return fHaveGrant;
  172. }
  173. };
  174. #endif