11debfc3dSmrg// <thread> -*- C++ -*- 21debfc3dSmrg 3*8feb0f0bSmrg// Copyright (C) 2008-2020 Free Software Foundation, Inc. 41debfc3dSmrg// 51debfc3dSmrg// This file is part of the GNU ISO C++ Library. This library is free 61debfc3dSmrg// software; you can redistribute it and/or modify it under the 71debfc3dSmrg// terms of the GNU General Public License as published by the 81debfc3dSmrg// Free Software Foundation; either version 3, or (at your option) 91debfc3dSmrg// any later version. 101debfc3dSmrg 111debfc3dSmrg// This library is distributed in the hope that it will be useful, 121debfc3dSmrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 131debfc3dSmrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141debfc3dSmrg// GNU General Public License for more details. 151debfc3dSmrg 161debfc3dSmrg// Under Section 7 of GPL version 3, you are granted additional 171debfc3dSmrg// permissions described in the GCC Runtime Library Exception, version 181debfc3dSmrg// 3.1, as published by the Free Software Foundation. 191debfc3dSmrg 201debfc3dSmrg// You should have received a copy of the GNU General Public License and 211debfc3dSmrg// a copy of the GCC Runtime Library Exception along with this program; 221debfc3dSmrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 231debfc3dSmrg// <http://www.gnu.org/licenses/>. 241debfc3dSmrg 251debfc3dSmrg/** @file include/thread 261debfc3dSmrg * This is a Standard C++ Library header. 271debfc3dSmrg */ 281debfc3dSmrg 291debfc3dSmrg#ifndef _GLIBCXX_THREAD 301debfc3dSmrg#define _GLIBCXX_THREAD 1 311debfc3dSmrg 321debfc3dSmrg#pragma GCC system_header 331debfc3dSmrg 341debfc3dSmrg#if __cplusplus < 201103L 351debfc3dSmrg# include <bits/c++0x_warning.h> 361debfc3dSmrg#else 371debfc3dSmrg 38*8feb0f0bSmrg#include <bits/c++config.h> 391debfc3dSmrg 40c0a68be4Smrg#if defined(_GLIBCXX_HAS_GTHREADS) 41*8feb0f0bSmrg#include <bits/gthr.h> 42*8feb0f0bSmrg 43*8feb0f0bSmrg#include <chrono> // std::chrono::* 44*8feb0f0bSmrg#include <memory> // std::unique_ptr 45*8feb0f0bSmrg#include <tuple> // std::tuple 46*8feb0f0bSmrg 47*8feb0f0bSmrg#if __cplusplus > 201703L 48*8feb0f0bSmrg# include <compare> // std::strong_ordering 49*8feb0f0bSmrg# include <stop_token> // std::stop_source, std::stop_token, std::nostopstate 50*8feb0f0bSmrg#endif 51*8feb0f0bSmrg 52*8feb0f0bSmrg#ifdef _GLIBCXX_USE_NANOSLEEP 53*8feb0f0bSmrg# include <cerrno> // errno, EINTR 54*8feb0f0bSmrg# include <time.h> // nanosleep 55*8feb0f0bSmrg#endif 56*8feb0f0bSmrg 57*8feb0f0bSmrg#include <bits/functional_hash.h> // std::hash 58*8feb0f0bSmrg#include <bits/invoke.h> // std::__invoke 591debfc3dSmrg 601debfc3dSmrgnamespace std _GLIBCXX_VISIBILITY(default) 611debfc3dSmrg{ 621debfc3dSmrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 631debfc3dSmrg 641debfc3dSmrg /** 651debfc3dSmrg * @defgroup threads Threads 661debfc3dSmrg * @ingroup concurrency 671debfc3dSmrg * 681debfc3dSmrg * Classes for thread support. 691debfc3dSmrg * @{ 701debfc3dSmrg */ 711debfc3dSmrg 721debfc3dSmrg /// thread 731debfc3dSmrg class thread 741debfc3dSmrg { 751debfc3dSmrg public: 761debfc3dSmrg // Abstract base class for types that wrap arbitrary functors to be 771debfc3dSmrg // invoked in the new thread of execution. 781debfc3dSmrg struct _State 791debfc3dSmrg { 801debfc3dSmrg virtual ~_State(); 811debfc3dSmrg virtual void _M_run() = 0; 821debfc3dSmrg }; 831debfc3dSmrg using _State_ptr = unique_ptr<_State>; 841debfc3dSmrg 851debfc3dSmrg typedef __gthread_t native_handle_type; 861debfc3dSmrg 871debfc3dSmrg /// thread::id 881debfc3dSmrg class id 891debfc3dSmrg { 901debfc3dSmrg native_handle_type _M_thread; 911debfc3dSmrg 921debfc3dSmrg public: 931debfc3dSmrg id() noexcept : _M_thread() { } 941debfc3dSmrg 951debfc3dSmrg explicit 961debfc3dSmrg id(native_handle_type __id) : _M_thread(__id) { } 971debfc3dSmrg 981debfc3dSmrg private: 991debfc3dSmrg friend class thread; 100*8feb0f0bSmrg friend class hash<id>; 1011debfc3dSmrg 1021debfc3dSmrg friend bool 103*8feb0f0bSmrg operator==(id __x, id __y) noexcept; 1041debfc3dSmrg 105*8feb0f0bSmrg#if __cpp_lib_three_way_comparison 106*8feb0f0bSmrg friend strong_ordering 107*8feb0f0bSmrg operator<=>(id __x, id __y) noexcept; 108*8feb0f0bSmrg#else 1091debfc3dSmrg friend bool 110*8feb0f0bSmrg operator<(id __x, id __y) noexcept; 111*8feb0f0bSmrg#endif 1121debfc3dSmrg 1131debfc3dSmrg template<class _CharT, class _Traits> 1141debfc3dSmrg friend basic_ostream<_CharT, _Traits>& 115*8feb0f0bSmrg operator<<(basic_ostream<_CharT, _Traits>& __out, id __id); 1161debfc3dSmrg }; 1171debfc3dSmrg 1181debfc3dSmrg private: 1191debfc3dSmrg id _M_id; 1201debfc3dSmrg 1211debfc3dSmrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 1221debfc3dSmrg // 2097. packaged_task constructors should be constrained 123c0a68be4Smrg // 3039. Unnecessary decay in thread and packaged_task 124a2dc1f3fSmrg template<typename _Tp> 125c0a68be4Smrg using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>; 1261debfc3dSmrg 127a2dc1f3fSmrg public: 128a2dc1f3fSmrg thread() noexcept = default; 1291debfc3dSmrg 130a2dc1f3fSmrg template<typename _Callable, typename... _Args, 131a2dc1f3fSmrg typename = _Require<__not_same<_Callable>>> 1321debfc3dSmrg explicit 1331debfc3dSmrg thread(_Callable&& __f, _Args&&... __args) 1341debfc3dSmrg { 135a2dc1f3fSmrg static_assert( __is_invocable<typename decay<_Callable>::type, 136a2dc1f3fSmrg typename decay<_Args>::type...>::value, 137a2dc1f3fSmrg "std::thread arguments must be invocable after conversion to rvalues" 138a2dc1f3fSmrg ); 139a2dc1f3fSmrg 1401debfc3dSmrg#ifdef GTHR_ACTIVE_PROXY 1411debfc3dSmrg // Create a reference to pthread_create, not just the gthr weak symbol. 1421debfc3dSmrg auto __depend = reinterpret_cast<void(*)()>(&pthread_create); 1431debfc3dSmrg#else 1441debfc3dSmrg auto __depend = nullptr; 1451debfc3dSmrg#endif 146*8feb0f0bSmrg // A call wrapper holding tuple{DECAY_COPY(__f), DECAY_COPY(__args)...} 147*8feb0f0bSmrg using _Invoker_type = _Invoker<__decayed_tuple<_Callable, _Args...>>; 148*8feb0f0bSmrg 149*8feb0f0bSmrg _M_start_thread(_S_make_state<_Invoker_type>( 150*8feb0f0bSmrg std::forward<_Callable>(__f), std::forward<_Args>(__args)...), 1511debfc3dSmrg __depend); 1521debfc3dSmrg } 1531debfc3dSmrg 1541debfc3dSmrg ~thread() 1551debfc3dSmrg { 1561debfc3dSmrg if (joinable()) 1571debfc3dSmrg std::terminate(); 1581debfc3dSmrg } 1591debfc3dSmrg 160a2dc1f3fSmrg thread(const thread&) = delete; 161a2dc1f3fSmrg 162a2dc1f3fSmrg thread(thread&& __t) noexcept 163a2dc1f3fSmrg { swap(__t); } 164a2dc1f3fSmrg 1651debfc3dSmrg thread& operator=(const thread&) = delete; 1661debfc3dSmrg 1671debfc3dSmrg thread& operator=(thread&& __t) noexcept 1681debfc3dSmrg { 1691debfc3dSmrg if (joinable()) 1701debfc3dSmrg std::terminate(); 1711debfc3dSmrg swap(__t); 1721debfc3dSmrg return *this; 1731debfc3dSmrg } 1741debfc3dSmrg 1751debfc3dSmrg void 1761debfc3dSmrg swap(thread& __t) noexcept 1771debfc3dSmrg { std::swap(_M_id, __t._M_id); } 1781debfc3dSmrg 1791debfc3dSmrg bool 1801debfc3dSmrg joinable() const noexcept 1811debfc3dSmrg { return !(_M_id == id()); } 1821debfc3dSmrg 1831debfc3dSmrg void 1841debfc3dSmrg join(); 1851debfc3dSmrg 1861debfc3dSmrg void 1871debfc3dSmrg detach(); 1881debfc3dSmrg 189*8feb0f0bSmrg id 1901debfc3dSmrg get_id() const noexcept 1911debfc3dSmrg { return _M_id; } 1921debfc3dSmrg 1931debfc3dSmrg /** @pre thread is joinable 1941debfc3dSmrg */ 1951debfc3dSmrg native_handle_type 1961debfc3dSmrg native_handle() 1971debfc3dSmrg { return _M_id._M_thread; } 1981debfc3dSmrg 1991debfc3dSmrg // Returns a value that hints at the number of hardware thread contexts. 2001debfc3dSmrg static unsigned int 2011debfc3dSmrg hardware_concurrency() noexcept; 2021debfc3dSmrg 2031debfc3dSmrg private: 2041debfc3dSmrg template<typename _Callable> 2051debfc3dSmrg struct _State_impl : public _State 2061debfc3dSmrg { 2071debfc3dSmrg _Callable _M_func; 2081debfc3dSmrg 209*8feb0f0bSmrg template<typename... _Args> 210*8feb0f0bSmrg _State_impl(_Args&&... __args) 211*8feb0f0bSmrg : _M_func{{std::forward<_Args>(__args)...}} 2121debfc3dSmrg { } 2131debfc3dSmrg 2141debfc3dSmrg void 2151debfc3dSmrg _M_run() { _M_func(); } 2161debfc3dSmrg }; 2171debfc3dSmrg 2181debfc3dSmrg void 2191debfc3dSmrg _M_start_thread(_State_ptr, void (*)()); 2201debfc3dSmrg 221*8feb0f0bSmrg template<typename _Callable, typename... _Args> 2221debfc3dSmrg static _State_ptr 223*8feb0f0bSmrg _S_make_state(_Args&&... __args) 2241debfc3dSmrg { 2251debfc3dSmrg using _Impl = _State_impl<_Callable>; 226*8feb0f0bSmrg return _State_ptr{new _Impl{std::forward<_Args>(__args)...}}; 2271debfc3dSmrg } 2281debfc3dSmrg#if _GLIBCXX_THREAD_ABI_COMPAT 2291debfc3dSmrg public: 2301debfc3dSmrg struct _Impl_base; 2311debfc3dSmrg typedef shared_ptr<_Impl_base> __shared_base_type; 2321debfc3dSmrg struct _Impl_base 2331debfc3dSmrg { 2341debfc3dSmrg __shared_base_type _M_this_ptr; 2351debfc3dSmrg virtual ~_Impl_base() = default; 2361debfc3dSmrg virtual void _M_run() = 0; 2371debfc3dSmrg }; 2381debfc3dSmrg 2391debfc3dSmrg private: 2401debfc3dSmrg void 2411debfc3dSmrg _M_start_thread(__shared_base_type, void (*)()); 2421debfc3dSmrg 2431debfc3dSmrg void 2441debfc3dSmrg _M_start_thread(__shared_base_type); 2451debfc3dSmrg#endif 2461debfc3dSmrg 2471debfc3dSmrg private: 2481debfc3dSmrg // A call wrapper that does INVOKE(forwarded tuple elements...) 2491debfc3dSmrg template<typename _Tuple> 2501debfc3dSmrg struct _Invoker 2511debfc3dSmrg { 2521debfc3dSmrg _Tuple _M_t; 2531debfc3dSmrg 254c0a68be4Smrg template<typename> 255c0a68be4Smrg struct __result; 256c0a68be4Smrg template<typename _Fn, typename... _Args> 257c0a68be4Smrg struct __result<tuple<_Fn, _Args...>> 258c0a68be4Smrg : __invoke_result<_Fn, _Args...> 259c0a68be4Smrg { }; 2601debfc3dSmrg 2611debfc3dSmrg template<size_t... _Ind> 262c0a68be4Smrg typename __result<_Tuple>::type 2631debfc3dSmrg _M_invoke(_Index_tuple<_Ind...>) 2641debfc3dSmrg { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); } 2651debfc3dSmrg 266c0a68be4Smrg typename __result<_Tuple>::type 267c0a68be4Smrg operator()() 268c0a68be4Smrg { 2691debfc3dSmrg using _Indices 2701debfc3dSmrg = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; 271c0a68be4Smrg return _M_invoke(_Indices()); 272c0a68be4Smrg } 2731debfc3dSmrg }; 2741debfc3dSmrg 2751debfc3dSmrg template<typename... _Tp> 276c0a68be4Smrg using __decayed_tuple = tuple<typename decay<_Tp>::type...>; 2771debfc3dSmrg 2781debfc3dSmrg public: 2791debfc3dSmrg // Returns a call wrapper that stores 2801debfc3dSmrg // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}. 2811debfc3dSmrg template<typename _Callable, typename... _Args> 2821debfc3dSmrg static _Invoker<__decayed_tuple<_Callable, _Args...>> 2831debfc3dSmrg __make_invoker(_Callable&& __callable, _Args&&... __args) 2841debfc3dSmrg { 2851debfc3dSmrg return { __decayed_tuple<_Callable, _Args...>{ 2861debfc3dSmrg std::forward<_Callable>(__callable), std::forward<_Args>(__args)... 2871debfc3dSmrg } }; 2881debfc3dSmrg } 2891debfc3dSmrg }; 2901debfc3dSmrg 2911debfc3dSmrg inline void 2921debfc3dSmrg swap(thread& __x, thread& __y) noexcept 2931debfc3dSmrg { __x.swap(__y); } 2941debfc3dSmrg 2951debfc3dSmrg inline bool 2961debfc3dSmrg operator==(thread::id __x, thread::id __y) noexcept 2971debfc3dSmrg { 2981debfc3dSmrg // pthread_equal is undefined if either thread ID is not valid, so we 2991debfc3dSmrg // can't safely use __gthread_equal on default-constructed values (nor 3001debfc3dSmrg // the non-zero value returned by this_thread::get_id() for 3011debfc3dSmrg // single-threaded programs using GNU libc). Assume EqualityComparable. 3021debfc3dSmrg return __x._M_thread == __y._M_thread; 3031debfc3dSmrg } 3041debfc3dSmrg 305*8feb0f0bSmrg#if __cpp_lib_three_way_comparison 306*8feb0f0bSmrg inline strong_ordering 307*8feb0f0bSmrg operator<=>(thread::id __x, thread::id __y) noexcept 308*8feb0f0bSmrg { return __x._M_thread <=> __y._M_thread; } 309*8feb0f0bSmrg#else 3101debfc3dSmrg inline bool 3111debfc3dSmrg operator!=(thread::id __x, thread::id __y) noexcept 3121debfc3dSmrg { return !(__x == __y); } 3131debfc3dSmrg 3141debfc3dSmrg inline bool 3151debfc3dSmrg operator<(thread::id __x, thread::id __y) noexcept 3161debfc3dSmrg { 3171debfc3dSmrg // Pthreads doesn't define any way to do this, so we just have to 3181debfc3dSmrg // assume native_handle_type is LessThanComparable. 3191debfc3dSmrg return __x._M_thread < __y._M_thread; 3201debfc3dSmrg } 3211debfc3dSmrg 3221debfc3dSmrg inline bool 3231debfc3dSmrg operator<=(thread::id __x, thread::id __y) noexcept 3241debfc3dSmrg { return !(__y < __x); } 3251debfc3dSmrg 3261debfc3dSmrg inline bool 3271debfc3dSmrg operator>(thread::id __x, thread::id __y) noexcept 3281debfc3dSmrg { return __y < __x; } 3291debfc3dSmrg 3301debfc3dSmrg inline bool 3311debfc3dSmrg operator>=(thread::id __x, thread::id __y) noexcept 3321debfc3dSmrg { return !(__x < __y); } 333*8feb0f0bSmrg#endif // __cpp_lib_three_way_comparison 3341debfc3dSmrg 3351debfc3dSmrg // DR 889. 3361debfc3dSmrg /// std::hash specialization for thread::id. 3371debfc3dSmrg template<> 3381debfc3dSmrg struct hash<thread::id> 3391debfc3dSmrg : public __hash_base<size_t, thread::id> 3401debfc3dSmrg { 3411debfc3dSmrg size_t 3421debfc3dSmrg operator()(const thread::id& __id) const noexcept 3431debfc3dSmrg { return std::_Hash_impl::hash(__id._M_thread); } 3441debfc3dSmrg }; 3451debfc3dSmrg 3461debfc3dSmrg template<class _CharT, class _Traits> 3471debfc3dSmrg inline basic_ostream<_CharT, _Traits>& 3481debfc3dSmrg operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) 3491debfc3dSmrg { 3501debfc3dSmrg if (__id == thread::id()) 3511debfc3dSmrg return __out << "thread::id of a non-executing thread"; 3521debfc3dSmrg else 3531debfc3dSmrg return __out << __id._M_thread; 3541debfc3dSmrg } 3551debfc3dSmrg 3561debfc3dSmrg /** @namespace std::this_thread 357*8feb0f0bSmrg * @brief ISO C++ 2011 namespace for interacting with the current thread 358*8feb0f0bSmrg * 359*8feb0f0bSmrg * C++11 30.3.2 [thread.thread.this] Namespace this_thread. 3601debfc3dSmrg */ 3611debfc3dSmrg namespace this_thread 3621debfc3dSmrg { 3631debfc3dSmrg /// get_id 3641debfc3dSmrg inline thread::id 3651debfc3dSmrg get_id() noexcept 3661debfc3dSmrg { 367*8feb0f0bSmrg#ifdef _GLIBCXX_NATIVE_THREAD_ID 368*8feb0f0bSmrg return thread::id(_GLIBCXX_NATIVE_THREAD_ID); 369*8feb0f0bSmrg#else 3701debfc3dSmrg return thread::id(__gthread_self()); 371*8feb0f0bSmrg#endif 3721debfc3dSmrg } 3731debfc3dSmrg 3741debfc3dSmrg /// yield 3751debfc3dSmrg inline void 3761debfc3dSmrg yield() noexcept 3771debfc3dSmrg { 3781debfc3dSmrg#ifdef _GLIBCXX_USE_SCHED_YIELD 3791debfc3dSmrg __gthread_yield(); 3801debfc3dSmrg#endif 3811debfc3dSmrg } 3821debfc3dSmrg 3831debfc3dSmrg void 3841debfc3dSmrg __sleep_for(chrono::seconds, chrono::nanoseconds); 3851debfc3dSmrg 3861debfc3dSmrg /// sleep_for 3871debfc3dSmrg template<typename _Rep, typename _Period> 3881debfc3dSmrg inline void 3891debfc3dSmrg sleep_for(const chrono::duration<_Rep, _Period>& __rtime) 3901debfc3dSmrg { 3911debfc3dSmrg if (__rtime <= __rtime.zero()) 3921debfc3dSmrg return; 3931debfc3dSmrg auto __s = chrono::duration_cast<chrono::seconds>(__rtime); 3941debfc3dSmrg auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s); 3951debfc3dSmrg#ifdef _GLIBCXX_USE_NANOSLEEP 3961debfc3dSmrg __gthread_time_t __ts = 3971debfc3dSmrg { 3981debfc3dSmrg static_cast<std::time_t>(__s.count()), 3991debfc3dSmrg static_cast<long>(__ns.count()) 4001debfc3dSmrg }; 4011debfc3dSmrg while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 4021debfc3dSmrg { } 4031debfc3dSmrg#else 4041debfc3dSmrg __sleep_for(__s, __ns); 4051debfc3dSmrg#endif 4061debfc3dSmrg } 4071debfc3dSmrg 4081debfc3dSmrg /// sleep_until 4091debfc3dSmrg template<typename _Clock, typename _Duration> 4101debfc3dSmrg inline void 4111debfc3dSmrg sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) 4121debfc3dSmrg { 413*8feb0f0bSmrg#if __cplusplus > 201703L 414*8feb0f0bSmrg static_assert(chrono::is_clock_v<_Clock>); 415*8feb0f0bSmrg#endif 4161debfc3dSmrg auto __now = _Clock::now(); 4171debfc3dSmrg if (_Clock::is_steady) 4181debfc3dSmrg { 4191debfc3dSmrg if (__now < __atime) 4201debfc3dSmrg sleep_for(__atime - __now); 4211debfc3dSmrg return; 4221debfc3dSmrg } 4231debfc3dSmrg while (__now < __atime) 4241debfc3dSmrg { 4251debfc3dSmrg sleep_for(__atime - __now); 4261debfc3dSmrg __now = _Clock::now(); 4271debfc3dSmrg } 4281debfc3dSmrg } 4291debfc3dSmrg } 4301debfc3dSmrg 431*8feb0f0bSmrg /// @} group threads 4321debfc3dSmrg 433*8feb0f0bSmrg#ifdef __cpp_lib_jthread 434*8feb0f0bSmrg 435*8feb0f0bSmrg class jthread 436*8feb0f0bSmrg { 437*8feb0f0bSmrg public: 438*8feb0f0bSmrg using id = thread::id; 439*8feb0f0bSmrg using native_handle_type = thread::native_handle_type; 440*8feb0f0bSmrg 441*8feb0f0bSmrg jthread() noexcept 442*8feb0f0bSmrg : _M_stop_source{nostopstate} 443*8feb0f0bSmrg { } 444*8feb0f0bSmrg 445*8feb0f0bSmrg template<typename _Callable, typename... _Args, 446*8feb0f0bSmrg typename = enable_if_t<!is_same_v<remove_cvref_t<_Callable>, 447*8feb0f0bSmrg jthread>>> 448*8feb0f0bSmrg explicit 449*8feb0f0bSmrg jthread(_Callable&& __f, _Args&&... __args) 450*8feb0f0bSmrg : _M_thread{_S_create(_M_stop_source, std::forward<_Callable>(__f), 451*8feb0f0bSmrg std::forward<_Args>(__args)...)} 452*8feb0f0bSmrg { } 453*8feb0f0bSmrg 454*8feb0f0bSmrg jthread(const jthread&) = delete; 455*8feb0f0bSmrg jthread(jthread&&) noexcept = default; 456*8feb0f0bSmrg 457*8feb0f0bSmrg ~jthread() 458*8feb0f0bSmrg { 459*8feb0f0bSmrg if (joinable()) 460*8feb0f0bSmrg { 461*8feb0f0bSmrg request_stop(); 462*8feb0f0bSmrg join(); 463*8feb0f0bSmrg } 464*8feb0f0bSmrg } 465*8feb0f0bSmrg 466*8feb0f0bSmrg jthread& 467*8feb0f0bSmrg operator=(const jthread&) = delete; 468*8feb0f0bSmrg 469*8feb0f0bSmrg jthread& 470*8feb0f0bSmrg operator=(jthread&& __other) noexcept 471*8feb0f0bSmrg { 472*8feb0f0bSmrg std::jthread(std::move(__other)).swap(*this); 473*8feb0f0bSmrg return *this; 474*8feb0f0bSmrg } 475*8feb0f0bSmrg 476*8feb0f0bSmrg void 477*8feb0f0bSmrg swap(jthread& __other) noexcept 478*8feb0f0bSmrg { 479*8feb0f0bSmrg std::swap(_M_stop_source, __other._M_stop_source); 480*8feb0f0bSmrg std::swap(_M_thread, __other._M_thread); 481*8feb0f0bSmrg } 482*8feb0f0bSmrg 483*8feb0f0bSmrg [[nodiscard]] bool 484*8feb0f0bSmrg joinable() const noexcept 485*8feb0f0bSmrg { 486*8feb0f0bSmrg return _M_thread.joinable(); 487*8feb0f0bSmrg } 488*8feb0f0bSmrg 489*8feb0f0bSmrg void 490*8feb0f0bSmrg join() 491*8feb0f0bSmrg { 492*8feb0f0bSmrg _M_thread.join(); 493*8feb0f0bSmrg } 494*8feb0f0bSmrg 495*8feb0f0bSmrg void 496*8feb0f0bSmrg detach() 497*8feb0f0bSmrg { 498*8feb0f0bSmrg _M_thread.detach(); 499*8feb0f0bSmrg } 500*8feb0f0bSmrg 501*8feb0f0bSmrg [[nodiscard]] id 502*8feb0f0bSmrg get_id() const noexcept 503*8feb0f0bSmrg { 504*8feb0f0bSmrg return _M_thread.get_id(); 505*8feb0f0bSmrg } 506*8feb0f0bSmrg 507*8feb0f0bSmrg [[nodiscard]] native_handle_type 508*8feb0f0bSmrg native_handle() 509*8feb0f0bSmrg { 510*8feb0f0bSmrg return _M_thread.native_handle(); 511*8feb0f0bSmrg } 512*8feb0f0bSmrg 513*8feb0f0bSmrg [[nodiscard]] static unsigned 514*8feb0f0bSmrg hardware_concurrency() noexcept 515*8feb0f0bSmrg { 516*8feb0f0bSmrg return thread::hardware_concurrency(); 517*8feb0f0bSmrg } 518*8feb0f0bSmrg 519*8feb0f0bSmrg [[nodiscard]] stop_source 520*8feb0f0bSmrg get_stop_source() noexcept 521*8feb0f0bSmrg { 522*8feb0f0bSmrg return _M_stop_source; 523*8feb0f0bSmrg } 524*8feb0f0bSmrg 525*8feb0f0bSmrg [[nodiscard]] stop_token 526*8feb0f0bSmrg get_stop_token() const noexcept 527*8feb0f0bSmrg { 528*8feb0f0bSmrg return _M_stop_source.get_token(); 529*8feb0f0bSmrg } 530*8feb0f0bSmrg 531*8feb0f0bSmrg bool request_stop() noexcept 532*8feb0f0bSmrg { 533*8feb0f0bSmrg return _M_stop_source.request_stop(); 534*8feb0f0bSmrg } 535*8feb0f0bSmrg 536*8feb0f0bSmrg friend void swap(jthread& __lhs, jthread& __rhs) noexcept 537*8feb0f0bSmrg { 538*8feb0f0bSmrg __lhs.swap(__rhs); 539*8feb0f0bSmrg } 540*8feb0f0bSmrg 541*8feb0f0bSmrg private: 542*8feb0f0bSmrg template<typename _Callable, typename... _Args> 543*8feb0f0bSmrg static thread 544*8feb0f0bSmrg _S_create(stop_source& __ssrc, _Callable&& __f, _Args&&... __args) 545*8feb0f0bSmrg { 546*8feb0f0bSmrg if constexpr(is_invocable_v<decay_t<_Callable>, stop_token, 547*8feb0f0bSmrg decay_t<_Args>...>) 548*8feb0f0bSmrg return thread{std::forward<_Callable>(__f), __ssrc.get_token(), 549*8feb0f0bSmrg std::forward<_Args>(__args)...}; 550*8feb0f0bSmrg else 551*8feb0f0bSmrg { 552*8feb0f0bSmrg static_assert(is_invocable_v<decay_t<_Callable>, 553*8feb0f0bSmrg decay_t<_Args>...>, 554*8feb0f0bSmrg "std::thread arguments must be invocable after" 555*8feb0f0bSmrg " conversion to rvalues"); 556*8feb0f0bSmrg return thread{std::forward<_Callable>(__f), 557*8feb0f0bSmrg std::forward<_Args>(__args)...}; 558*8feb0f0bSmrg } 559*8feb0f0bSmrg } 560*8feb0f0bSmrg 561*8feb0f0bSmrg stop_source _M_stop_source; 562*8feb0f0bSmrg thread _M_thread; 563*8feb0f0bSmrg }; 564*8feb0f0bSmrg#endif // __cpp_lib_jthread 565a2dc1f3fSmrg_GLIBCXX_END_NAMESPACE_VERSION 5661debfc3dSmrg} // namespace 567c0a68be4Smrg#endif // _GLIBCXX_HAS_GTHREADS 5681debfc3dSmrg#endif // C++11 5691debfc3dSmrg#endif // _GLIBCXX_THREAD 570