CriSec.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : https://github.com/ldcsaa
  6. * Project : https://github.com/ldcsaa/HP-Socket
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 44636872, 75375912
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. #pragma once
  24. #include "../hpsocket/GlobalDef.h"
  25. #include "Singleton.h"
  26. #include "FuncHelper.h"
  27. #include <mutex>
  28. #include <atomic>
  29. using namespace std;
  30. class CSpinGuard
  31. {
  32. public:
  33. CSpinGuard() : m_atFlag(FALSE)
  34. {
  35. }
  36. ~CSpinGuard()
  37. {
  38. ASSERT(!m_atFlag);
  39. }
  40. void Lock(BOOL bWeek = TRUE, memory_order m = memory_order_acquire)
  41. {
  42. for(UINT i = 0; !TryLock(bWeek, m); ++i)
  43. YieldThread(i);
  44. }
  45. BOOL TryLock(BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
  46. {
  47. BOOL bExpect = FALSE;
  48. return bWeek
  49. ? m_atFlag.compare_exchange_weak(bExpect, TRUE, m)
  50. : m_atFlag.compare_exchange_strong(bExpect, TRUE, m);
  51. }
  52. void Unlock(memory_order m = memory_order_release)
  53. {
  54. ASSERT(m_atFlag);
  55. m_atFlag.store(FALSE, m);
  56. }
  57. DECLARE_NO_COPY_CLASS(CSpinGuard)
  58. private:
  59. atomic<BOOL> m_atFlag;
  60. };
  61. class CReentrantSpinGuard
  62. {
  63. public:
  64. CReentrantSpinGuard()
  65. : m_atThreadID (0)
  66. , m_iCount (0)
  67. {
  68. }
  69. ~CReentrantSpinGuard()
  70. {
  71. ASSERT(m_atThreadID == 0);
  72. ASSERT(m_iCount == 0);
  73. }
  74. void Lock(BOOL bWeek = TRUE, memory_order m = memory_order_acquire)
  75. {
  76. for(UINT i = 0; !_TryLock(i == 0, bWeek, m); ++i)
  77. YieldThread(i);
  78. }
  79. BOOL TryLock(BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
  80. {
  81. return _TryLock(TRUE, bWeek, m);
  82. }
  83. void Unlock(memory_order m = memory_order_release)
  84. {
  85. ASSERT(::IsSelfThread(m_atThreadID));
  86. if((--m_iCount) == 0)
  87. m_atThreadID.store(0, m);
  88. }
  89. private:
  90. BOOL _TryLock(BOOL bFirst, BOOL bWeek = FALSE, memory_order m = memory_order_acquire)
  91. {
  92. THR_ID dwCurrentThreadID = SELF_THREAD_ID;
  93. if(bFirst && ::IsSameThread(m_atThreadID, dwCurrentThreadID))
  94. {
  95. ++m_iCount;
  96. return TRUE;
  97. }
  98. THR_ID ulExpect = 0;
  99. BOOL isOK = bWeek
  100. ? m_atThreadID.compare_exchange_weak(ulExpect, dwCurrentThreadID, m)
  101. : m_atThreadID.compare_exchange_strong(ulExpect, dwCurrentThreadID, m);
  102. if(isOK)
  103. {
  104. ASSERT(m_iCount == 0);
  105. m_iCount = 1;
  106. return TRUE;
  107. }
  108. return FALSE;
  109. }
  110. DECLARE_NO_COPY_CLASS(CReentrantSpinGuard)
  111. private:
  112. atomic_tid m_atThreadID;
  113. int m_iCount;
  114. };
  115. class CFakeGuard
  116. {
  117. public:
  118. void Lock() {}
  119. void Unlock() {}
  120. BOOL TryLock() {return TRUE;}
  121. };
  122. template<class CLockObj> class CLocalLock
  123. {
  124. public:
  125. CLocalLock(CLockObj& obj) : m_lock(obj) {m_lock.Lock();}
  126. ~CLocalLock() {m_lock.Unlock();}
  127. private:
  128. CLockObj& m_lock;
  129. };
  130. template<class CLockObj> class CLocalTryLock
  131. {
  132. public:
  133. CLocalTryLock(CLockObj& obj) : m_lock(obj) {m_bValid = m_lock.TryLock();}
  134. ~CLocalTryLock() {if(m_bValid) m_lock.Unlock();}
  135. BOOL IsValid() {return m_bValid;}
  136. private:
  137. CLockObj& m_lock;
  138. BOOL m_bValid;
  139. };
  140. template<class CMTXObj> class CMTXTryLock
  141. {
  142. public:
  143. CMTXTryLock(CMTXObj& obj) : m_lock(obj) {m_bValid = m_lock.try_lock();}
  144. ~CMTXTryLock() {if(m_bValid) m_lock.unlock();}
  145. BOOL IsValid() {return m_bValid;}
  146. private:
  147. CMTXObj& m_lock;
  148. BOOL m_bValid;
  149. };
  150. using CSpinLock = CLocalLock<CSpinGuard>;
  151. using CReentrantSpinLock = CLocalLock<CReentrantSpinGuard>;
  152. using CFakeLock = CLocalLock<CFakeGuard>;
  153. using CCriSec = mutex;
  154. using CCriSecLock = lock_guard<mutex>;
  155. using CCriSecLock2 = unique_lock<mutex>;
  156. using CCriSecTryLock = CMTXTryLock<mutex>;
  157. using CMTX = CCriSec;
  158. using CMutexLock = CCriSecLock;
  159. using CMutexLock2 = CCriSecLock2;
  160. using CMutexTryLock = CCriSecTryLock;
  161. using CReentrantCriSec = recursive_mutex;
  162. using CReentrantCriSecLock = lock_guard<recursive_mutex>;
  163. using CReentrantCriSecLock2 = unique_lock<recursive_mutex>;
  164. using CReentrantCriSecTryLock = CMTXTryLock<recursive_mutex>;
  165. using CReentrantMTX = CReentrantCriSec;
  166. using CReentrantMutexLock = CReentrantCriSecLock;
  167. using CReentrantMutexLock2 = CReentrantCriSecLock2;
  168. using CReentrantMutexTryLock = CReentrantCriSecTryLock;
  169. template<typename T, typename = enable_if_t<is_arithmetic<T>::value>> class CSafeCounterT
  170. {
  171. public:
  172. T Increment() {return ::InterlockedIncrement(&m_iCount);}
  173. T Decrement() {return ::InterlockedDecrement(&m_iCount);}
  174. T AddFetch(T iCount) {return ::InterlockedAdd(&m_iCount, iCount);}
  175. T SubFetch(T iCount) {return ::InterlockedSub(&m_iCount, iCount);}
  176. T FetchAdd(T iCount) {return ::InterlockedExchangeAdd(&m_iCount, iCount);}
  177. T FetchSub(T iCount) {return ::InterlockedExchangeSub(&m_iCount, iCount);}
  178. T SetCount(T iCount) {return (m_iCount = iCount);}
  179. T ResetCount() {return SetCount(0);}
  180. T GetCount() {return m_iCount;}
  181. T operator ++ () {return Increment();}
  182. T operator -- () {return Decrement();}
  183. T operator ++ (int) {return FetchAdd(1);}
  184. T operator -- (int) {return FetchSub(1);}
  185. T operator += (T iCount) {return AddFetch(iCount);}
  186. T operator -= (T iCount) {return SubFetch(iCount);}
  187. T operator = (T iCount) {return SetCount(iCount);}
  188. operator T () {return GetCount();}
  189. public:
  190. CSafeCounterT(T iCount = 0) : m_iCount(iCount) {}
  191. protected:
  192. volatile T m_iCount;
  193. };
  194. template<typename T, typename = enable_if_t<is_arithmetic<T>::value>> class CUnsafeCounterT
  195. {
  196. public:
  197. T Increment() {return ++m_iCount;}
  198. T Decrement() {return --m_iCount;}
  199. T AddFetch(T iCount) {return m_iCount += iCount;}
  200. T SubFetch(T iCount) {return m_iCount -= iCount;}
  201. T FetchAdd(T iCount) {T rs = m_iCount; m_iCount += iCount; return rs;}
  202. T FetchSub(T iCount) {T rs = m_iCount; m_iCount -= iCount; return rs;}
  203. T SetCount(T iCount) {return (m_iCount = iCount);}
  204. T ResetCount() {return SetCount(0);}
  205. T GetCount() {return m_iCount;}
  206. T operator ++ () {return Increment();}
  207. T operator -- () {return Decrement();}
  208. T operator ++ (int) {return FetchAdd(1);}
  209. T operator -- (int) {return FetchSub(1);}
  210. T operator += (T iCount) {return AddFetch(iCount);}
  211. T operator -= (T iCount) {return SubFetch(iCount);}
  212. T operator = (T iCount) {return SetCount(iCount);}
  213. operator T () {return GetCount();}
  214. public:
  215. CUnsafeCounterT(T iCount = 0) : m_iCount(iCount) {}
  216. protected:
  217. T m_iCount;
  218. };
  219. template<class CCounter> class CLocalCounter
  220. {
  221. public:
  222. CLocalCounter(CCounter& obj) : m_counter(obj) {m_counter.Increment();}
  223. ~CLocalCounter() {m_counter.Decrement();}
  224. private:
  225. CCounter& m_counter;
  226. };
  227. using CSafeCounter = CSafeCounterT<INT>;
  228. using CSafeBigCounter = CSafeCounterT<LONGLONG>;
  229. using CUnsafeCounter = CUnsafeCounterT<INT>;
  230. using CUnsafeBigCounter = CUnsafeCounterT<LONGLONG>;
  231. using CLocalSafeCounter = CLocalCounter<CSafeCounter>;
  232. using CLocalSafeBigCounter = CLocalCounter<CSafeBigCounter>;
  233. using CLocalUnsafeCounter = CLocalCounter<CUnsafeCounter>;
  234. using CLocalUnsafeBigCounter = CLocalCounter<CUnsafeBigCounter>;