CriticalSection.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 2.3.15
  5. * Author : Bruce Liang
  6. * Website : http://www.jessma.org
  7. * Project : https://github.com/ldcsaa
  8. * Blog : http://www.cnblogs.com/ldcsaa
  9. * Wiki : http://www.oschina.net/p/hp-socket
  10. * QQ Group : 75375912
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. #pragma once
  25. #include <intrin.h>
  26. #pragma intrinsic(_ReadBarrier)
  27. #pragma intrinsic(_WriteBarrier)
  28. #pragma intrinsic(_ReadWriteBarrier)
  29. #define DEFAULT_CRISEC_SPIN_COUNT 4096
  30. #if defined (_WIN64)
  31. #define DEFAULT_PAUSE_RETRY 16
  32. #define DEFAULT_PAUSE_YIELD 128
  33. #define DEFAULT_PAUSE_CYCLE 8192
  34. #else
  35. #define DEFAULT_PAUSE_RETRY 4
  36. #define DEFAULT_PAUSE_YIELD 32
  37. #define DEFAULT_PAUSE_CYCLE 4096
  38. #endif
  39. #ifndef YieldProcessor
  40. #pragma intrinsic(_mm_pause)
  41. #define YieldProcessor _mm_pause
  42. #endif
  43. static inline void YieldThread(UINT i = DEFAULT_PAUSE_RETRY)
  44. {
  45. if (i < DEFAULT_PAUSE_RETRY) ;
  46. else if (i < DEFAULT_PAUSE_YIELD) YieldProcessor();
  47. else if (i < DEFAULT_PAUSE_CYCLE - 1) SwitchToThread();
  48. else if (i < DEFAULT_PAUSE_CYCLE) Sleep(1);
  49. else YieldThread(i & (DEFAULT_PAUSE_CYCLE - 1));
  50. }
  51. class CInterCriSec
  52. {
  53. public:
  54. CInterCriSec(DWORD dwSpinCount = DEFAULT_CRISEC_SPIN_COUNT)
  55. {VERIFY(::InitializeCriticalSectionAndSpinCount(&m_crisec, dwSpinCount));}
  56. ~CInterCriSec()
  57. {::DeleteCriticalSection(&m_crisec);}
  58. void Lock() {::EnterCriticalSection(&m_crisec);}
  59. void Unlock() {::LeaveCriticalSection(&m_crisec);}
  60. BOOL TryLock() {return ::TryEnterCriticalSection(&m_crisec);}
  61. DWORD SetSpinCount(DWORD dwSpinCount) {return ::SetCriticalSectionSpinCount(&m_crisec, dwSpinCount);}
  62. CRITICAL_SECTION* GetObject() {return &m_crisec;}
  63. private:
  64. CInterCriSec(const CInterCriSec& cs);
  65. CInterCriSec operator = (const CInterCriSec& cs);
  66. private:
  67. CRITICAL_SECTION m_crisec;
  68. };
  69. class CInterCriSec2
  70. {
  71. public:
  72. CInterCriSec2(DWORD dwSpinCount = DEFAULT_CRISEC_SPIN_COUNT, BOOL bInitialize = TRUE)
  73. {
  74. if(bInitialize)
  75. {
  76. m_pcrisec = new CRITICAL_SECTION;
  77. VERIFY(::InitializeCriticalSectionAndSpinCount(m_pcrisec, dwSpinCount));
  78. }
  79. else
  80. m_pcrisec = nullptr;
  81. }
  82. ~CInterCriSec2() {Reset();}
  83. void Attach(CRITICAL_SECTION* pcrisec)
  84. {
  85. Reset();
  86. m_pcrisec = pcrisec;
  87. }
  88. CRITICAL_SECTION* Detach()
  89. {
  90. CRITICAL_SECTION* pcrisec = m_pcrisec;
  91. m_pcrisec = nullptr;
  92. return pcrisec;
  93. }
  94. void Lock() {::EnterCriticalSection(m_pcrisec);}
  95. void Unlock() {::LeaveCriticalSection(m_pcrisec);}
  96. BOOL TryLock() {return ::TryEnterCriticalSection(m_pcrisec);}
  97. DWORD SetSpinCount(DWORD dwSpinCount) {return ::SetCriticalSectionSpinCount(m_pcrisec, dwSpinCount);}
  98. CRITICAL_SECTION* GetObject() {return m_pcrisec;}
  99. private:
  100. CInterCriSec2(const CInterCriSec2& cs);
  101. CInterCriSec2 operator = (const CInterCriSec2& cs);
  102. void Reset()
  103. {
  104. if(m_pcrisec)
  105. {
  106. ::DeleteCriticalSection(m_pcrisec);
  107. delete m_pcrisec;
  108. m_pcrisec = nullptr;
  109. }
  110. }
  111. private:
  112. CRITICAL_SECTION* m_pcrisec;
  113. };
  114. class CMTX
  115. {
  116. public:
  117. CMTX(BOOL bInitialOwner = FALSE, LPCTSTR pszName = nullptr, LPSECURITY_ATTRIBUTES pSecurity = nullptr)
  118. {
  119. m_hMutex = ::CreateMutex(pSecurity, bInitialOwner, pszName);
  120. ASSERT(IsValid());
  121. }
  122. ~CMTX()
  123. {
  124. if(IsValid())
  125. ::CloseHandle(m_hMutex);
  126. }
  127. BOOL Open(DWORD dwAccess, BOOL bInheritHandle, LPCTSTR pszName)
  128. {
  129. if(IsValid())
  130. VERIFY(::CloseHandle(m_hMutex));
  131. m_hMutex = ::OpenMutex(dwAccess, bInheritHandle, pszName);
  132. return(IsValid());
  133. }
  134. void Lock(DWORD dwMilliseconds = INFINITE) {::WaitForSingleObject(m_hMutex, dwMilliseconds);}
  135. void Unlock() {::ReleaseMutex(m_hMutex);}
  136. HANDLE& GetHandle () {return m_hMutex;}
  137. operator HANDLE () {return m_hMutex;}
  138. BOOL IsValid () {return m_hMutex != nullptr;}
  139. private:
  140. CMTX(const CMTX& mtx);
  141. CMTX operator = (const CMTX& mtx);
  142. private:
  143. HANDLE m_hMutex;
  144. };
  145. class CSpinGuard
  146. {
  147. public:
  148. CSpinGuard() : m_lFlag(0)
  149. {
  150. }
  151. ~CSpinGuard()
  152. {
  153. ASSERT(m_lFlag == 0);
  154. }
  155. void Lock()
  156. {
  157. for(UINT i = 0; !TryLock(); ++i)
  158. YieldThread(i);
  159. }
  160. BOOL TryLock()
  161. {
  162. if(::InterlockedCompareExchange(&m_lFlag, 1, 0) == 0)
  163. {
  164. ::_ReadWriteBarrier();
  165. return TRUE;
  166. }
  167. return FALSE;
  168. }
  169. void Unlock()
  170. {
  171. ASSERT(m_lFlag == 1);
  172. m_lFlag = 0;
  173. }
  174. private:
  175. CSpinGuard(const CSpinGuard& cs);
  176. CSpinGuard operator = (const CSpinGuard& cs);
  177. private:
  178. volatile LONG m_lFlag;
  179. };
  180. class CReentrantSpinGuard
  181. {
  182. public:
  183. CReentrantSpinGuard()
  184. : m_dwThreadID (0)
  185. , m_iCount (0)
  186. {
  187. }
  188. ~CReentrantSpinGuard()
  189. {
  190. ASSERT(m_dwThreadID == 0);
  191. ASSERT(m_iCount == 0);
  192. }
  193. void Lock()
  194. {
  195. for(UINT i = 0; !_TryLock(i == 0); ++i)
  196. YieldThread(i);
  197. }
  198. BOOL TryLock()
  199. {
  200. return _TryLock(TRUE);
  201. }
  202. void Unlock()
  203. {
  204. ASSERT(m_dwThreadID == ::GetCurrentThreadId());
  205. if((--m_iCount) == 0)
  206. m_dwThreadID = 0;
  207. }
  208. private:
  209. CReentrantSpinGuard(const CReentrantSpinGuard& cs);
  210. CReentrantSpinGuard operator = (const CReentrantSpinGuard& cs);
  211. BOOL _TryLock(BOOL bFirst)
  212. {
  213. DWORD dwCurrentThreadID = ::GetCurrentThreadId();
  214. if(bFirst && m_dwThreadID == dwCurrentThreadID)
  215. {
  216. ++m_iCount;
  217. return TRUE;
  218. }
  219. if(::InterlockedCompareExchange(&m_dwThreadID, dwCurrentThreadID, 0) == 0)
  220. {
  221. ::_ReadWriteBarrier();
  222. ASSERT(m_iCount == 0);
  223. m_iCount = 1;
  224. return TRUE;
  225. }
  226. return FALSE;
  227. }
  228. private:
  229. volatile DWORD m_dwThreadID;
  230. int m_iCount;
  231. };
  232. class CFakeGuard
  233. {
  234. public:
  235. void Lock() {}
  236. void Unlock() {}
  237. BOOL TryLock() {return TRUE;}
  238. };
  239. template<class CLockObj> class CLocalLock
  240. {
  241. public:
  242. CLocalLock(CLockObj& obj) : m_lock(obj) {m_lock.Lock();}
  243. ~CLocalLock() {m_lock.Unlock();}
  244. private:
  245. CLockObj& m_lock;
  246. };
  247. typedef CInterCriSec CCriSec;
  248. typedef CLocalLock<CCriSec> CCriSecLock;
  249. typedef CLocalLock<CInterCriSec> CInterCriSecLock;
  250. typedef CLocalLock<CInterCriSec2> CInterCriSecLock2;
  251. typedef CLocalLock<CMTX> CMutexLock;
  252. typedef CLocalLock<CSpinGuard> CSpinLock;
  253. typedef CLocalLock<CReentrantSpinGuard> CReentrantSpinLock;
  254. typedef CLocalLock<CFakeGuard> CFakeLock;