// thread standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _THREAD_ #define _THREAD_ #include #if _STL_COMPILER_PREPROCESSOR #include #include #include #include #include #ifdef _M_CEE_PURE #error is not supported when compiling with /clr:pure. #endif // _M_CEE_PURE #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN class thread { // class for observing and managing threads public: class id; using native_handle_type = void*; thread() noexcept : _Thr{} {} private: template static unsigned int __stdcall _Invoke(void* _RawVals) noexcept /* terminates */ { // adapt invoke of user's callable object to _beginthreadex's thread procedure const unique_ptr<_Tuple> _FnVals(static_cast<_Tuple*>(_RawVals)); _Tuple& _Tup = *_FnVals; _STD invoke(_STD move(_STD get<_Indices>(_Tup))...); _Cnd_do_broadcast_at_thread_exit(); // TRANSITION, ABI return 0; } template _NODISCARD static constexpr auto _Get_invoke(index_sequence<_Indices...>) noexcept { return &_Invoke<_Tuple, _Indices...>; } public: template , thread>, int> = 0> explicit thread(_Fn&& _Fx, _Args&&... _Ax) { using _Tuple = tuple, decay_t<_Args>...>; auto _Decay_copied = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{}); #pragma warning(push) #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to // extern C function under -EHc. Undefined behavior may occur // if this function throws an exception. (/Wall) _Thr._Hnd = reinterpret_cast(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id)); #pragma warning(pop) if (_Thr._Hnd) { // ownership transferred to the thread (void) _Decay_copied.release(); } else { // failed to start thread _Thr._Id = 0; _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN); } } ~thread() noexcept { if (joinable()) { _STD terminate(); } } thread(thread&& _Other) noexcept : _Thr(_STD exchange(_Other._Thr, {})) {} thread& operator=(thread&& _Other) noexcept { if (joinable()) { _STD terminate(); } _Thr = _STD exchange(_Other._Thr, {}); return *this; } thread(const thread&) = delete; thread& operator=(const thread&) = delete; void swap(thread& _Other) noexcept { _STD swap(_Thr, _Other._Thr); } _NODISCARD bool joinable() const noexcept { return _Thr._Id != 0; } void join() { if (!joinable()) { _Throw_Cpp_error(_INVALID_ARGUMENT); } if (_Thr._Id == _Thrd_id()) { _Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR); } if (_Thrd_join(_Thr, nullptr) != _Thrd_success) { _Throw_Cpp_error(_NO_SUCH_PROCESS); } _Thr = {}; } void detach() { if (!joinable()) { _Throw_Cpp_error(_INVALID_ARGUMENT); } _Check_C_return(_Thrd_detach(_Thr)); _Thr = {}; } _NODISCARD id get_id() const noexcept; _NODISCARD static unsigned int hardware_concurrency() noexcept { return _Thrd_hardware_concurrency(); } _NODISCARD native_handle_type native_handle() { // return Win32 HANDLE as void * return _Thr._Hnd; } private: _Thrd_t _Thr; }; namespace this_thread { _NODISCARD thread::id get_id() noexcept; inline void yield() noexcept { _Thrd_yield(); } inline void sleep_until(const xtime* _Abs_time) { _Thrd_sleep(_Abs_time); } template void sleep_until(const chrono::time_point<_Clock, _Duration>& _Abs_time) { for (;;) { const auto _Now = _Clock::now(); if (_Abs_time <= _Now) { return; } _CSTD xtime _Tgt; (void) _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now); _Thrd_sleep(&_Tgt); } } template void sleep_for(const chrono::duration<_Rep, _Period>& _Rel_time) { sleep_until(chrono::steady_clock::now() + _Rel_time); } } // namespace this_thread class thread::id { // thread id public: id() noexcept : _Id(0) { // id for no thread } private: id(_Thrd_id_t _Other_id) : _Id(_Other_id) {} _Thrd_id_t _Id; friend thread::id thread::get_id() const noexcept; friend thread::id this_thread::get_id() noexcept; friend bool operator==(thread::id _Left, thread::id _Right) noexcept; friend bool operator<(thread::id _Left, thread::id _Right) noexcept; template friend basic_ostream<_Ch, _Tr>& operator<<(basic_ostream<_Ch, _Tr>& _Str, thread::id _Id); friend hash; }; _NODISCARD inline thread::id thread::get_id() const noexcept { return _Thr._Id; } _NODISCARD inline thread::id this_thread::get_id() noexcept { return _Thrd_id(); } inline void swap(thread& _Left, thread& _Right) noexcept { _Left.swap(_Right); } _NODISCARD inline bool operator==(thread::id _Left, thread::id _Right) noexcept { return _Left._Id == _Right._Id; } _NODISCARD inline bool operator!=(thread::id _Left, thread::id _Right) noexcept { return !(_Left == _Right); } _NODISCARD inline bool operator<(thread::id _Left, thread::id _Right) noexcept { return _Left._Id < _Right._Id; } _NODISCARD inline bool operator<=(thread::id _Left, thread::id _Right) noexcept { return !(_Right < _Left); } _NODISCARD inline bool operator>(thread::id _Left, thread::id _Right) noexcept { return _Right < _Left; } _NODISCARD inline bool operator>=(thread::id _Left, thread::id _Right) noexcept { return !(_Left < _Right); } template basic_ostream<_Ch, _Tr>& operator<<(basic_ostream<_Ch, _Tr>& _Str, thread::id _Id) { return _Str << _Id._Id; } // STRUCT TEMPLATE SPECIALIZATION hash template <> struct hash { _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef thread::id _ARGUMENT_TYPE_NAME; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME; _NODISCARD size_t operator()(const thread::id _Keyval) const noexcept { return _Hash_representation(_Keyval._Id); } }; _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _THREAD_