Thread.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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 <process.h>
  26. #include "RWLock.h"
  27. #include "STLHelper.h"
  28. template<class T> class CThread
  29. {
  30. public:
  31. BOOL Start(T* pRunner, int iPriority = THREAD_PRIORITY_NORMAL, UINT uiStackSize = 0, LPSECURITY_ATTRIBUTES lpThreadAttributes = nullptr)
  32. {
  33. BOOL isOK = TRUE;
  34. if(!IsRunning())
  35. {
  36. Release();
  37. if(iPriority == THREAD_PRIORITY_NORMAL)
  38. m_hThread = (HANDLE)_beginthreadex(lpThreadAttributes, uiStackSize, ThreadProc, (LPVOID)pRunner, 0, &m_uiThreadID);
  39. else
  40. {
  41. m_hThread = (HANDLE)_beginthreadex(lpThreadAttributes, uiStackSize, ThreadProc, (LPVOID)pRunner, CREATE_SUSPENDED, &m_uiThreadID);
  42. if(IsValid())
  43. {
  44. ::SetThreadPriority(m_hThread, iPriority);
  45. ::ResumeThread(m_hThread);
  46. }
  47. }
  48. if(IsValid())
  49. m_pRunner = pRunner;
  50. else
  51. {
  52. ::SetLastError(_doserrno);
  53. isOK = FALSE;
  54. }
  55. }
  56. else
  57. {
  58. ::SetLastError(ERROR_INVALID_STATE);
  59. isOK = FALSE;
  60. }
  61. return isOK;
  62. }
  63. BOOL Join(BOOL bWithMessageLoop = FALSE, DWORD dwMilliseconds = INFINITE)
  64. {
  65. BOOL isOK = bWithMessageLoop ?
  66. ::MsgWaitForSingleObject(m_hThread, dwMilliseconds) :
  67. ::WaitForSingleObject(m_hThread, dwMilliseconds) == WAIT_OBJECT_0 ;
  68. Release();
  69. return isOK;
  70. }
  71. BOOL IsRunning()
  72. {
  73. if(!IsValid())
  74. return FALSE;
  75. DWORD dwExitCode;
  76. if(GetExitCode(&dwExitCode))
  77. return dwExitCode == STILL_ACTIVE;
  78. return FALSE;
  79. }
  80. VOID Release()
  81. {
  82. if(IsValid())
  83. {
  84. ::CloseHandle(m_hThread);
  85. Reset();
  86. }
  87. }
  88. HANDLE Detatch()
  89. {
  90. HANDLE h = m_hThread;
  91. Reset();
  92. return h;
  93. }
  94. BOOL Terminate (DWORD dwExitCode) {return ::TerminateThread(m_hThread, dwExitCode);}
  95. BOOL GetExitCode (LPDWORD lpExitCode) {return ::GetExitCodeThread(m_hThread, lpExitCode);}
  96. DWORD Suspend () {return ::SuspendThread(m_hThread);}
  97. DWORD Resume () {return ::ResumeThread(m_hThread);}
  98. BOOL IsValid () {return m_hThread != nullptr;}
  99. T* GetRunner () {return m_pRunner;}
  100. DWORD GetThreadID () {return m_uiThreadID;}
  101. HANDLE& GetThreadHandle () {return m_hThread;}
  102. const HANDLE& GetThreadHandle () const {return m_hThread;}
  103. public:
  104. CThread()
  105. {
  106. Reset();
  107. }
  108. virtual ~CThread()
  109. {
  110. Release();
  111. }
  112. private:
  113. static UINT WINAPI ThreadProc(LPVOID pv)
  114. {
  115. return ((T*)pv)->Run();
  116. }
  117. void Reset()
  118. {
  119. m_uiThreadID = 0;
  120. m_hThread = nullptr;
  121. m_pRunner = nullptr;
  122. }
  123. private:
  124. UINT m_uiThreadID;
  125. HANDLE m_hThread;
  126. T* m_pRunner;
  127. DECLARE_NO_COPY_CLASS(CThread)
  128. };
  129. template<class T, typename construct_param_type = void*> class CTlsObj
  130. {
  131. typedef unordered_map<DWORD, T*> TLocalMap;
  132. typedef typename TLocalMap::iterator TLocalMapI;
  133. typedef typename TLocalMap::const_iterator TLocalMapCI;
  134. public:
  135. T* TryGet(DWORD dwTID = 0)
  136. {
  137. T* pValue = nullptr;
  138. if(dwTID == 0) dwTID = ::GetCurrentThreadId();
  139. {
  140. CReadLock locallock(m_lock);
  141. TLocalMapCI it = m_map.find(dwTID);
  142. if(it != m_map.end())
  143. pValue = it->second;
  144. }
  145. return pValue;
  146. }
  147. T* Get()
  148. {
  149. DWORD dwTID = ::GetCurrentThreadId();
  150. T* pValue = TryGet(dwTID);
  151. if(pValue == nullptr)
  152. {
  153. CWriteLock locallock(m_lock);
  154. TLocalMapCI it = m_map.find(dwTID);
  155. if(it != m_map.end())
  156. pValue = it->second;
  157. if(pValue == nullptr)
  158. {
  159. pValue = Construct();
  160. m_map[dwTID] = pValue;
  161. }
  162. }
  163. return pValue;
  164. }
  165. T& GetRef()
  166. {
  167. return *Get();
  168. }
  169. T* Get(construct_param_type construct_param)
  170. {
  171. DWORD dwTID = ::GetCurrentThreadId();
  172. T* pValue = TryGet(dwTID);
  173. if(pValue == nullptr)
  174. {
  175. CWriteLock locallock(m_lock);
  176. TLocalMapCI it = m_map.find(dwTID);
  177. if(it != m_map.end())
  178. pValue = it->second;
  179. if(pValue == nullptr)
  180. {
  181. pValue = ConstructWithParam(construct_param);
  182. m_map[dwTID] = pValue;
  183. }
  184. }
  185. return pValue;
  186. }
  187. T& GetRef(construct_param_type construct_param)
  188. {
  189. return *Get(construct_param);
  190. }
  191. T* SetAndRetriveOldValue(T* pValue)
  192. {
  193. DWORD dwTID = ::GetCurrentThreadId();
  194. T* pOldValue = TryGet(dwTID);
  195. if(pValue != pOldValue)
  196. {
  197. CWriteLock locallock(m_lock);
  198. m_map[dwTID] = pValue;
  199. }
  200. return pOldValue;
  201. }
  202. void Set(T* pValue)
  203. {
  204. T* pOldValue = SetAndRetriveOldValue(pValue);
  205. if(pValue != pOldValue)
  206. Delete(pOldValue);
  207. }
  208. void Remove()
  209. {
  210. DWORD dwTID = ::GetCurrentThreadId();
  211. T* pOldValue = TryGet(dwTID);
  212. Delete(pOldValue);
  213. {
  214. CWriteLock locallock(m_lock);
  215. m_map.erase(dwTID);
  216. }
  217. }
  218. void Clear()
  219. {
  220. CWriteLock locallock(m_lock);
  221. if(!IsEmpty())
  222. {
  223. for(TLocalMapCI it = m_map.begin(); it != m_map.end(); ++it)
  224. Delete(it->second);
  225. m_map.clear();
  226. }
  227. }
  228. TLocalMap& GetLocalMap() {return m_map;}
  229. const TLocalMap& GetLocalMap() const {return m_map;}
  230. T* operator -> () {return Get();}
  231. const T* operator -> () const {return Get();}
  232. T& operator * () {return GetRef();}
  233. const T& operator * () const {return GetRef();}
  234. size_t Size () const {return m_map.size();}
  235. bool IsEmpty () const {return m_map.empty();}
  236. public:
  237. CTlsObj()
  238. {
  239. }
  240. ~CTlsObj()
  241. {
  242. Clear();
  243. }
  244. private:
  245. static inline void Delete(T* pValue)
  246. {
  247. if(pValue != nullptr)
  248. delete pValue;
  249. }
  250. static inline T* Construct()
  251. {
  252. return new T;
  253. }
  254. static inline T* ConstructWithParam(construct_param_type construct_param)
  255. {
  256. return new T(construct_param);
  257. }
  258. private:
  259. CSimpleRWLock m_lock;
  260. TLocalMap m_map;
  261. DECLARE_NO_COPY_CLASS(CTlsObj)
  262. };