mingw_threads.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /**
  2. * @file mingw.thread.h
  3. * @brief std::thread implementation for MinGW
  4. * (c) 2013-2016 by Mega Limited, Auckland, New Zealand
  5. * @author Alexander Vassilev
  6. *
  7. * @copyright Simplified (2-clause) BSD License.
  8. * You should have received a copy of the license along with this
  9. * program.
  10. *
  11. * This code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * @note
  15. * This file may become part of the mingw-w64 runtime package. If/when this happens,
  16. * the appropriate license will be added, i.e. this code will become dual-licensed,
  17. * and the current BSD 2-clause license will stay.
  18. */
  19. #ifndef WIN32STDTHREAD_H
  20. #define WIN32STDTHREAD_H
  21. #if !defined(__cplusplus) || (__cplusplus < 201103L)
  22. #error A C++11 compiler is required!
  23. #endif
  24. // Use the standard classes for std::, if available.
  25. #include <thread>
  26. #include <cstddef> // For std::size_t
  27. #include <cerrno> // Detect error type.
  28. #include <exception> // For std::terminate
  29. #include <system_error> // For std::system_error
  30. #include <functional> // For std::hash
  31. #include <tuple> // For std::tuple
  32. #include <chrono> // For sleep timing.
  33. #include <memory> // For std::unique_ptr
  34. #include <iosfwd> // Stream output for thread ids.
  35. #include <utility> // For std::swap, std::forward
  36. #include "mingw_invoke.hpp"
  37. #if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
  38. #pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
  39. with Microsoft's API. We'll try to work around this, but we can make no\
  40. guarantees. This problem does not exist in MinGW-w64."
  41. #include <windows.h> // No further granularity can be expected.
  42. #else
  43. #include <synchapi.h> // For WaitForSingleObject
  44. #include <handleapi.h> // For CloseHandle, etc.
  45. #include <sysinfoapi.h> // For GetNativeSystemInfo
  46. #include <processthreadsapi.h> // For GetCurrentThreadId
  47. #endif
  48. #include <process.h> // For _beginthreadex
  49. #ifndef NDEBUG
  50. #include <cstdio>
  51. #endif
  52. #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)
  53. #error To use the MinGW-std-threads library, you will need to define the macro _WIN32_WINNT to be 0x0501 (Windows XP) or higher.
  54. #endif
  55. // Instead of INVALID_HANDLE_VALUE, _beginthreadex returns 0.
  56. namespace mingw_stdthread
  57. {
  58. namespace detail
  59. {
  60. template<std::size_t...>
  61. struct IntSeq {};
  62. template<std::size_t N, std::size_t... S>
  63. struct GenIntSeq : GenIntSeq<N-1, N-1, S...> { };
  64. template<std::size_t... S>
  65. struct GenIntSeq<0, S...> { typedef IntSeq<S...> type; };
  66. // Use a template specialization to avoid relying on compiler optimization
  67. // when determining the parameter integer sequence.
  68. template<class Func, class T, typename... Args>
  69. class ThreadFuncCall;
  70. // We can't define the Call struct in the function - the standard forbids template methods in that case
  71. template<class Func, std::size_t... S, typename... Args>
  72. class ThreadFuncCall<Func, detail::IntSeq<S...>, Args...>
  73. {
  74. static_assert(sizeof...(S) == sizeof...(Args), "Args must match.");
  75. using Tuple = std::tuple<typename std::decay<Args>::type...>;
  76. typename std::decay<Func>::type mFunc;
  77. Tuple mArgs;
  78. public:
  79. ThreadFuncCall(Func&& aFunc, Args&&... aArgs)
  80. : mFunc(std::forward<Func>(aFunc)),
  81. mArgs(std::forward<Args>(aArgs)...)
  82. {
  83. }
  84. void callFunc()
  85. {
  86. detail::invoke(std::move(mFunc), std::move(std::get<S>(mArgs)) ...);
  87. }
  88. };
  89. // Allow construction of threads without exposing implementation.
  90. class ThreadIdTool;
  91. } // Namespace "detail"
  92. class thread
  93. {
  94. public:
  95. class id
  96. {
  97. DWORD mId = 0;
  98. friend class thread;
  99. friend class std::hash<id>;
  100. friend class detail::ThreadIdTool;
  101. explicit id(DWORD aId) noexcept : mId(aId){}
  102. public:
  103. id (void) noexcept = default;
  104. friend bool operator==(id x, id y) noexcept {return x.mId == y.mId; }
  105. friend bool operator!=(id x, id y) noexcept {return x.mId != y.mId; }
  106. friend bool operator< (id x, id y) noexcept {return x.mId < y.mId; }
  107. friend bool operator<=(id x, id y) noexcept {return x.mId <= y.mId; }
  108. friend bool operator> (id x, id y) noexcept {return x.mId > y.mId; }
  109. friend bool operator>=(id x, id y) noexcept {return x.mId >= y.mId; }
  110. template<class _CharT, class _Traits>
  111. friend std::basic_ostream<_CharT, _Traits>&
  112. operator<<(std::basic_ostream<_CharT, _Traits>& __out, id __id)
  113. {
  114. if (__id.mId == 0)
  115. {
  116. return __out << "(invalid std::thread::id)";
  117. }
  118. else
  119. {
  120. return __out << __id.mId;
  121. }
  122. }
  123. };
  124. private:
  125. static constexpr HANDLE kInvalidHandle = nullptr;
  126. static constexpr DWORD kInfinite = 0xffffffffl;
  127. HANDLE mHandle;
  128. id mThreadId;
  129. template <class Call>
  130. static unsigned __stdcall threadfunc(void* arg)
  131. {
  132. std::unique_ptr<Call> call(static_cast<Call*>(arg));
  133. call->callFunc();
  134. return 0;
  135. }
  136. static unsigned int _hardware_concurrency_helper() noexcept
  137. {
  138. SYSTEM_INFO sysinfo;
  139. // This is one of the few functions used by the library which has a nearly-
  140. // equivalent function defined in earlier versions of Windows. Include the
  141. // workaround, just as a reminder that it does exist.
  142. #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
  143. ::GetNativeSystemInfo(&sysinfo);
  144. #else
  145. ::GetSystemInfo(&sysinfo);
  146. #endif
  147. return sysinfo.dwNumberOfProcessors;
  148. }
  149. public:
  150. typedef HANDLE native_handle_type;
  151. id get_id() const noexcept {return mThreadId;}
  152. native_handle_type native_handle() const {return mHandle;}
  153. thread(): mHandle(kInvalidHandle), mThreadId(){}
  154. thread(thread&& other)
  155. :mHandle(other.mHandle), mThreadId(other.mThreadId)
  156. {
  157. other.mHandle = kInvalidHandle;
  158. other.mThreadId = id{};
  159. }
  160. thread(const thread &other)=delete;
  161. template<class Func, typename... Args>
  162. explicit thread(Func&& func, Args&&... args) : mHandle(), mThreadId()
  163. {
  164. using ArgSequence = typename detail::GenIntSeq<sizeof...(Args)>::type;
  165. using Call = detail::ThreadFuncCall<Func, ArgSequence, Args...>;
  166. auto call = new Call(
  167. std::forward<Func>(func), std::forward<Args>(args)...);
  168. unsigned id_receiver;
  169. auto int_handle = _beginthreadex(NULL, 0, threadfunc<Call>,
  170. static_cast<LPVOID>(call), 0, &id_receiver);
  171. if (int_handle == 0)
  172. {
  173. mHandle = kInvalidHandle;
  174. int errnum = errno;
  175. delete call;
  176. // Note: Should only throw EINVAL, EAGAIN, EACCES
  177. throw std::system_error(errnum, std::generic_category());
  178. } else {
  179. mThreadId.mId = id_receiver;
  180. mHandle = reinterpret_cast<HANDLE>(int_handle);
  181. }
  182. }
  183. bool joinable() const {return mHandle != kInvalidHandle;}
  184. // Note: Due to lack of synchronization, this function has a race condition
  185. // if called concurrently, which leads to undefined behavior. The same applies
  186. // to all other member functions of this class, but this one is mentioned
  187. // explicitly.
  188. void join()
  189. {
  190. using namespace std;
  191. if (get_id() == id(GetCurrentThreadId()))
  192. throw system_error(make_error_code(errc::resource_deadlock_would_occur));
  193. if (mHandle == kInvalidHandle)
  194. throw system_error(make_error_code(errc::no_such_process));
  195. if (!joinable())
  196. throw system_error(make_error_code(errc::invalid_argument));
  197. WaitForSingleObject(mHandle, kInfinite);
  198. CloseHandle(mHandle);
  199. mHandle = kInvalidHandle;
  200. mThreadId = id{};
  201. }
  202. ~thread()
  203. {
  204. if (joinable())
  205. {
  206. #ifndef NDEBUG
  207. std::printf("Error: Must join() or detach() a thread before \
  208. destroying it.\n");
  209. #endif
  210. std::terminate();
  211. }
  212. }
  213. thread& operator=(const thread&) = delete;
  214. thread& operator=(thread&& other) noexcept
  215. {
  216. if (joinable())
  217. {
  218. #ifndef NDEBUG
  219. std::printf("Error: Must join() or detach() a thread before \
  220. moving another thread to it.\n");
  221. #endif
  222. std::terminate();
  223. }
  224. swap(std::forward<thread>(other));
  225. return *this;
  226. }
  227. void swap(thread&& other) noexcept
  228. {
  229. std::swap(mHandle, other.mHandle);
  230. std::swap(mThreadId.mId, other.mThreadId.mId);
  231. }
  232. static unsigned int hardware_concurrency() noexcept
  233. {
  234. static unsigned int cached = _hardware_concurrency_helper();
  235. return cached;
  236. }
  237. void detach()
  238. {
  239. if (!joinable())
  240. {
  241. using namespace std;
  242. throw system_error(make_error_code(errc::invalid_argument));
  243. }
  244. if (mHandle != kInvalidHandle)
  245. {
  246. CloseHandle(mHandle);
  247. mHandle = kInvalidHandle;
  248. }
  249. mThreadId = id{};
  250. }
  251. };
  252. namespace detail
  253. {
  254. class ThreadIdTool
  255. {
  256. public:
  257. static thread::id make_id (DWORD base_id) noexcept
  258. {
  259. return thread::id(base_id);
  260. }
  261. };
  262. } // Namespace "detail"
  263. namespace this_thread
  264. {
  265. inline thread::id get_id() noexcept
  266. {
  267. return detail::ThreadIdTool::make_id(GetCurrentThreadId());
  268. }
  269. inline void yield() noexcept {Sleep(0);}
  270. template< class Rep, class Period >
  271. void sleep_for( const std::chrono::duration<Rep,Period>& sleep_duration)
  272. {
  273. static constexpr DWORD kInfinite = 0xffffffffl;
  274. using namespace std::chrono;
  275. using rep = milliseconds::rep;
  276. rep ms = duration_cast<milliseconds>(sleep_duration).count();
  277. while (ms > 0)
  278. {
  279. constexpr rep kMaxRep = static_cast<rep>(kInfinite - 1);
  280. auto sleepTime = (ms < kMaxRep) ? ms : kMaxRep;
  281. Sleep(static_cast<DWORD>(sleepTime));
  282. ms -= sleepTime;
  283. }
  284. }
  285. template <class Clock, class Duration>
  286. void sleep_until(const std::chrono::time_point<Clock,Duration>& sleep_time)
  287. {
  288. sleep_for(sleep_time-Clock::now());
  289. }
  290. }
  291. } // Namespace mingw_stdthread
  292. namespace std
  293. {
  294. // Because of quirks of the compiler, the common "using namespace std;"
  295. // directive would flatten the namespaces and introduce ambiguity where there
  296. // was none. Direct specification (std::), however, would be unaffected.
  297. // Take the safe option, and include only in the presence of MinGW's win32
  298. // implementation.
  299. #if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS)
  300. using mingw_stdthread::thread;
  301. // Remove ambiguity immediately, to avoid problems arising from the above.
  302. //using std::thread;
  303. namespace this_thread
  304. {
  305. using namespace mingw_stdthread::this_thread;
  306. }
  307. #elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
  308. #define MINGW_STDTHREAD_REDUNDANCY_WARNING
  309. #pragma message "This version of MinGW seems to include a win32 port of\
  310. pthreads, and probably already has C++11 std threading classes implemented,\
  311. based on pthreads. These classes, found in namespace std, are not overridden\
  312. by the mingw-std-thread library. If you would still like to use this\
  313. implementation (as it is more lightweight), use the classes provided in\
  314. namespace mingw_stdthread."
  315. #endif
  316. // Specialize hash for this implementation's thread::id, even if the
  317. // std::thread::id already has a hash.
  318. template<>
  319. struct hash<mingw_stdthread::thread::id>
  320. {
  321. typedef mingw_stdthread::thread::id argument_type;
  322. typedef size_t result_type;
  323. size_t operator() (const argument_type & i) const noexcept
  324. {
  325. return i.mId;
  326. }
  327. };
  328. }
  329. #endif // WIN32STDTHREAD_H