Thread.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. #pragma once
  12. /** @file Thread.h
  13. @brief The Thread class. Implements threading either using Boost, native Win32 or pthreads constructs. */
  14. // Modified by Lasse Oorni for Urho3D
  15. #include <string>
  16. #ifdef KNET_USE_BOOST
  17. #include <boost/thread.hpp>
  18. #else
  19. #ifdef WIN32
  20. // Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
  21. #include <windows.h>
  22. #else
  23. #include <pthread.h>
  24. #endif
  25. #include "Event.h"
  26. namespace kNet
  27. {
  28. typedef void (*ThreadEntryFunc)(void *threadStartData);
  29. }
  30. #endif
  31. #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
  32. #include "SharedPtr.h"
  33. namespace kNet
  34. {
  35. #if defined(KNET_USE_BOOST) && defined(KNET_ENABLE_WINXP_SUPPORT)
  36. typedef boost::thread::id ThreadId;
  37. #elif defined(WIN32)
  38. typedef DWORD ThreadId; // Don't use boost::thread::id on Windows even if KNET_USE_BOOST is #defined, since it has issues identifying threads across dll boundaries.
  39. #elif defined(KNET_USE_BOOST)
  40. typedef boost::thread::id ThreadId;
  41. #else
  42. typedef pthread_t ThreadId;
  43. #endif
  44. std::string ThreadIdToString(const ThreadId &id);
  45. class Thread : public RefCountable
  46. {
  47. public:
  48. Thread();
  49. ~Thread();
  50. /// Call this function only from inside the thread that is running. Returns true if the worker thread
  51. /// should exit immediately.
  52. bool ShouldQuit() const;
  53. /// Callable from either the thread owner or the thread itself.
  54. bool IsRunning() const;
  55. /// Suspends the thread until 'Resume()' is called. Call this function from the main thread.
  56. void Hold();
  57. /// Resumes the thread that is being held.
  58. void Resume();
  59. /// Makes the worker thread sleep if this thread is held, until this thread is resumed. Only callable
  60. /// from the worker thread.
  61. void CheckHold();
  62. /// Tries first to gracefully close the thread (waits for a while), and forcefully terminates the thread if
  63. /// it didn't respond in that time. \todo Allow specifying the timeout period.
  64. void Stop();
  65. /// Sets the name of this thread. This method is implemented for debugging purposes only, and does not do anything
  66. /// if running outside Visual Studio debugger.
  67. void SetName(const char *name);
  68. template<typename Class, typename MemberFuncPtr, typename FuncParam>
  69. void Run(Class *obj, MemberFuncPtr memberFuncPtr, const FuncParam &param);
  70. template<typename Class, typename MemberFuncPtr>
  71. void Run(Class *obj, MemberFuncPtr memberFuncPtr);
  72. template<typename FuncPtr, typename FuncParam, typename FuncParam2>
  73. void RunFunc(FuncPtr funcPtr, const FuncParam &param, const FuncParam2 &param2);
  74. template<typename FuncPtr, typename FuncParam>
  75. void RunFunc(FuncPtr funcPtr, const FuncParam &param);
  76. template<typename FuncPtr>
  77. void RunFunc(FuncPtr funcPtr);
  78. /// Sleeps the current thread for the given amount of time, or interrupts the sleep if the thread was signalled
  79. /// to quit in between.
  80. static void Sleep(int msecs);
  81. ThreadId Id();
  82. static ThreadId CurrentThreadId();
  83. static ThreadId NullThreadId();
  84. private:
  85. Thread(const Thread &);
  86. void operator =(const Thread &);
  87. class ObjInvokeBase : public RefCountable
  88. {
  89. public:
  90. virtual void Invoke() = 0;
  91. virtual ~ObjInvokeBase() {}
  92. void operator()()
  93. {
  94. Invoke();
  95. }
  96. };
  97. template<typename FuncPtr>
  98. class FuncInvokerVoid : public ObjInvokeBase
  99. {
  100. public:
  101. FuncPtr funcPtr;
  102. FuncInvokerVoid(FuncPtr funcPtr_)
  103. :funcPtr(funcPtr_){}
  104. virtual void Invoke() { funcPtr(); }
  105. };
  106. template<typename FuncPtr, typename FuncParam>
  107. class FuncInvokerUnary : public ObjInvokeBase
  108. {
  109. public:
  110. FuncPtr funcPtr;
  111. FuncParam param;
  112. FuncInvokerUnary(FuncPtr funcPtr_, const FuncParam &param_)
  113. :funcPtr(funcPtr_), param(param_){}
  114. virtual void Invoke() { funcPtr(param); }
  115. };
  116. template<typename FuncPtr, typename FuncParam, typename FuncParam2>
  117. class FuncInvokerBinary : public ObjInvokeBase
  118. {
  119. public:
  120. FuncPtr funcPtr;
  121. FuncParam param;
  122. FuncParam2 param2;
  123. FuncInvokerBinary(FuncPtr funcPtr_, const FuncParam &param_, const FuncParam2 &param2_)
  124. :funcPtr(funcPtr_), param(param_), param2(param2_){}
  125. virtual void Invoke() { funcPtr(param, param2); }
  126. };
  127. template<typename Class, typename MemberFuncPtr>
  128. class ClassInvokerVoid : public ObjInvokeBase
  129. {
  130. public:
  131. Class *obj;
  132. MemberFuncPtr memberFuncPtr;
  133. ClassInvokerVoid(Class *obj_, MemberFuncPtr memberFuncPtr_)
  134. :obj(obj_), memberFuncPtr(memberFuncPtr_){}
  135. virtual void Invoke() { CALL_MEMBER_FN(*obj, memberFuncPtr)(); }
  136. };
  137. template<typename Class, typename MemberFuncPtr, typename FuncParam>
  138. class ClassInvokerUnary : public ObjInvokeBase
  139. {
  140. public:
  141. Class *obj;
  142. MemberFuncPtr memberFuncPtr;
  143. FuncParam param;
  144. ClassInvokerUnary(Class *obj_, MemberFuncPtr memberFuncPtr_, const FuncParam &param_)
  145. :obj(obj_), memberFuncPtr(memberFuncPtr_), param(param_){}
  146. virtual void Invoke() { CALL_MEMBER_FN(*obj, memberFuncPtr)(param); }
  147. };
  148. ObjInvokeBase *invoker;
  149. // The following objects are used to implement thread suspendion/holding.
  150. Event threadHoldEvent;
  151. Event threadHoldEventAcked;
  152. Event threadResumeEvent;
  153. void StartThread();
  154. #ifdef KNET_USE_BOOST
  155. boost::thread thread;
  156. #elif defined(WIN32)
  157. HANDLE threadHandle;
  158. ThreadId threadId;
  159. /// The entry point that is called from the trampoline. Do not call this function.
  160. void _ThreadRun();
  161. friend DWORD WINAPI ThreadEntryPoint(LPVOID lpParameter);
  162. private:
  163. bool threadEnabled;
  164. #else
  165. pthread_t thread;
  166. void _ThreadRun();
  167. friend void* ThreadEntryPoint(void* data);
  168. private:
  169. bool threadEnabled;
  170. #endif
  171. };
  172. template<typename Class, typename MemberFuncPtr, typename FuncParam>
  173. void Thread::Run(Class *obj, MemberFuncPtr memberFuncPtr, const FuncParam &param)
  174. {
  175. Stop();
  176. invoker = new ClassInvokerUnary<Class, MemberFuncPtr, FuncParam>(obj, memberFuncPtr, param);
  177. StartThread();
  178. }
  179. template<typename Class, typename MemberFuncPtr>
  180. void Thread::Run(Class *obj, MemberFuncPtr memberFuncPtr)
  181. {
  182. Stop();
  183. invoker = new ClassInvokerVoid<Class, MemberFuncPtr>(obj, memberFuncPtr);
  184. StartThread();
  185. }
  186. template<typename FuncPtr, typename FuncParam, typename FuncParam2>
  187. void Thread::RunFunc(FuncPtr funcPtr, const FuncParam &param, const FuncParam2 &param2)
  188. {
  189. Stop();
  190. invoker = new FuncInvokerBinary<FuncPtr, FuncParam, FuncParam2>(funcPtr, param, param2);
  191. StartThread();
  192. }
  193. template<typename FuncPtr, typename FuncParam>
  194. void Thread::RunFunc(FuncPtr funcPtr, const FuncParam &param)
  195. {
  196. Stop();
  197. invoker = new FuncInvokerUnary<FuncPtr, FuncParam>(funcPtr, param);
  198. StartThread();
  199. }
  200. template<typename FuncPtr>
  201. void Thread::RunFunc(FuncPtr funcPtr)
  202. {
  203. Stop();
  204. invoker = new FuncInvokerVoid<FuncPtr>(funcPtr);
  205. StartThread();
  206. }
  207. } // ~kNet