std_thread.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #ifndef STD_THREAD_H_
  2. #define STD_THREAD_H_
  3. #define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
  4. #define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
  5. #ifndef __has_include
  6. #define __has_include(s) 0
  7. #endif
  8. #if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
  9. // GCC 4.4 provides <thread>
  10. #ifndef _GLIBCXX_USE_SCHED_YIELD
  11. #define _GLIBCXX_USE_SCHED_YIELD
  12. #endif
  13. #include <thread>
  14. #elif __has_include(<thread>) && !ANDROID
  15. // Clang + libc++
  16. #include <thread>
  17. #else
  18. // partial std::thread implementation for win32/pthread
  19. #include <algorithm>
  20. #if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
  21. #define USE_RVALUE_REFERENCES
  22. #endif
  23. #ifdef __APPLE__
  24. #import <Foundation/NSAutoreleasePool.h>
  25. #endif
  26. #if defined(_WIN32)
  27. // WIN32
  28. #define WIN32_LEAN_AND_MEAN
  29. #include <Windows.h>
  30. #if defined(_MSC_VER) && defined(_MT)
  31. // When linking with LIBCMT (the multithreaded C library), Microsoft recommends
  32. // using _beginthreadex instead of CreateThread.
  33. #define USE_BEGINTHREADEX
  34. #include <process.h>
  35. #endif
  36. #ifdef USE_BEGINTHREADEX
  37. #define THREAD_ID unsigned
  38. #define THREAD_RETURN unsigned __stdcall
  39. #else
  40. #define THREAD_ID DWORD
  41. #define THREAD_RETURN DWORD WINAPI
  42. #endif
  43. #define THREAD_HANDLE HANDLE
  44. #else
  45. // PTHREAD
  46. #include <unistd.h>
  47. #ifndef _POSIX_THREADS
  48. #error unsupported platform (no pthreads?)
  49. #endif
  50. #include <pthread.h>
  51. #define THREAD_ID pthread_t
  52. #define THREAD_HANDLE pthread_t
  53. #define THREAD_RETURN void*
  54. #endif
  55. namespace std
  56. {
  57. class thread
  58. {
  59. public:
  60. typedef THREAD_HANDLE native_handle_type;
  61. class id
  62. {
  63. friend class thread;
  64. public:
  65. id() : m_thread(0) {}
  66. id(THREAD_ID _id) : m_thread(_id) {}
  67. bool operator==(const id& rhs) const
  68. {
  69. return m_thread == rhs.m_thread;
  70. }
  71. bool operator!=(const id& rhs) const
  72. {
  73. return !(*this == rhs);
  74. }
  75. bool operator<(const id& rhs) const
  76. {
  77. return m_thread < rhs.m_thread;
  78. }
  79. private:
  80. THREAD_ID m_thread;
  81. };
  82. // no variadic template support in msvc
  83. //template <typename C, typename... A>
  84. //thread(C&& func, A&&... args);
  85. template <typename C>
  86. thread(C func)
  87. {
  88. StartThread(new Func<C>(func));
  89. }
  90. template <typename C, typename A>
  91. thread(C func, A arg)
  92. {
  93. StartThread(new FuncArg<C, A>(func, arg));
  94. }
  95. thread() /*= default;*/ {}
  96. #ifdef USE_RVALUE_REFERENCES
  97. thread(const thread&) /*= delete*/;
  98. thread(thread&& other)
  99. {
  100. #else
  101. thread(const thread& t)
  102. {
  103. // ugly const_cast to get around lack of rvalue references
  104. thread& other = const_cast<thread&>(t);
  105. #endif
  106. swap(other);
  107. }
  108. #ifdef USE_RVALUE_REFERENCES
  109. thread& operator=(const thread&) /*= delete*/;
  110. thread& operator=(thread&& other)
  111. {
  112. #else
  113. thread& operator=(const thread& t)
  114. {
  115. // ugly const_cast to get around lack of rvalue references
  116. thread& other = const_cast<thread&>(t);
  117. #endif
  118. if (joinable())
  119. detach();
  120. swap(other);
  121. return *this;
  122. }
  123. ~thread()
  124. {
  125. if (joinable())
  126. detach();
  127. }
  128. bool joinable() const
  129. {
  130. return m_id != id();
  131. }
  132. id get_id() const
  133. {
  134. return m_id;
  135. }
  136. native_handle_type native_handle()
  137. {
  138. #ifdef _WIN32
  139. return m_handle;
  140. #else
  141. return m_id.m_thread;
  142. #endif
  143. }
  144. void join()
  145. {
  146. #ifdef _WIN32
  147. WaitForSingleObject(m_handle, INFINITE);
  148. detach();
  149. #else
  150. pthread_join(m_id.m_thread, NULL);
  151. m_id = id();
  152. #endif
  153. }
  154. void detach()
  155. {
  156. #ifdef _WIN32
  157. CloseHandle(m_handle);
  158. #else
  159. pthread_detach(m_id.m_thread);
  160. #endif
  161. m_id = id();
  162. }
  163. void swap(thread& other)
  164. {
  165. std::swap(m_id, other.m_id);
  166. #ifdef _WIN32
  167. std::swap(m_handle, other.m_handle);
  168. #endif
  169. }
  170. static unsigned hardware_concurrency()
  171. {
  172. #ifdef _WIN32
  173. SYSTEM_INFO sysinfo;
  174. GetSystemInfo(&sysinfo);
  175. return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
  176. #else
  177. return 0;
  178. #endif
  179. }
  180. private:
  181. id m_id;
  182. #ifdef _WIN32
  183. native_handle_type m_handle;
  184. #endif
  185. template <typename F>
  186. void StartThread(F* param)
  187. {
  188. #ifdef USE_BEGINTHREADEX
  189. m_handle = (HANDLE)_beginthreadex(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
  190. #elif defined(_WIN32)
  191. m_handle = CreateThread(NULL, 0, &RunAndDelete<F>, param, 0, &m_id.m_thread);
  192. #else
  193. pthread_attr_t attr;
  194. pthread_attr_init(&attr);
  195. pthread_attr_setstacksize(&attr, 1024 * 1024);
  196. if (pthread_create(&m_id.m_thread, &attr, &RunAndDelete<F>, param))
  197. m_id = id();
  198. #endif
  199. }
  200. template <typename C>
  201. class Func
  202. {
  203. public:
  204. Func(C _func) : func(_func) {}
  205. void Run() { func(); }
  206. private:
  207. C const func;
  208. };
  209. template <typename C, typename A>
  210. class FuncArg
  211. {
  212. public:
  213. FuncArg(C _func, A _arg) : func(_func), arg(_arg) {}
  214. void Run() { func(arg); }
  215. private:
  216. C const func;
  217. A arg;
  218. };
  219. template <typename F>
  220. static THREAD_RETURN RunAndDelete(void* param)
  221. {
  222. #ifdef __APPLE__
  223. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  224. #endif
  225. static_cast<F*>(param)->Run();
  226. delete static_cast<F*>(param);
  227. #ifdef __APPLE__
  228. [pool release];
  229. #endif
  230. return 0;
  231. }
  232. };
  233. namespace this_thread
  234. {
  235. inline void yield()
  236. {
  237. #ifdef _WIN32
  238. SwitchToThread();
  239. #else
  240. sleep(0);
  241. #endif
  242. }
  243. inline thread::id get_id()
  244. {
  245. #ifdef _WIN32
  246. return GetCurrentThreadId();
  247. #else
  248. return pthread_self();
  249. #endif
  250. }
  251. } // namespace this_thread
  252. } // namespace std
  253. #undef USE_RVALUE_REFERENCES
  254. #undef USE_BEGINTHREADEX
  255. #undef THREAD_ID
  256. #undef THREAD_RETURN
  257. #undef THREAD_HANDLE
  258. #endif
  259. #endif