110d565efSmrg// <thread> -*- C++ -*- 210d565efSmrg 3*ec02198aSmrg// Copyright (C) 2008-2020 Free Software Foundation, Inc. 410d565efSmrg// 510d565efSmrg// This file is part of the GNU ISO C++ Library. This library is free 610d565efSmrg// software; you can redistribute it and/or modify it under the 710d565efSmrg// terms of the GNU General Public License as published by the 810d565efSmrg// Free Software Foundation; either version 3, or (at your option) 910d565efSmrg// any later version. 1010d565efSmrg 1110d565efSmrg// This library is distributed in the hope that it will be useful, 1210d565efSmrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 1310d565efSmrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1410d565efSmrg// GNU General Public License for more details. 1510d565efSmrg 1610d565efSmrg// Under Section 7 of GPL version 3, you are granted additional 1710d565efSmrg// permissions described in the GCC Runtime Library Exception, version 1810d565efSmrg// 3.1, as published by the Free Software Foundation. 1910d565efSmrg 2010d565efSmrg// You should have received a copy of the GNU General Public License and 2110d565efSmrg// a copy of the GCC Runtime Library Exception along with this program; 2210d565efSmrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 2310d565efSmrg// <http://www.gnu.org/licenses/>. 2410d565efSmrg 2510d565efSmrg/** @file include/thread 2610d565efSmrg * This is a Standard C++ Library header. 2710d565efSmrg */ 2810d565efSmrg 2910d565efSmrg#ifndef _GLIBCXX_THREAD 3010d565efSmrg#define _GLIBCXX_THREAD 1 3110d565efSmrg 3210d565efSmrg#pragma GCC system_header 3310d565efSmrg 3410d565efSmrg#if __cplusplus < 201103L 3510d565efSmrg# include <bits/c++0x_warning.h> 3610d565efSmrg#else 3710d565efSmrg 38*ec02198aSmrg#include <bits/c++config.h> 3910d565efSmrg 400fc04c29Smrg#if defined(_GLIBCXX_HAS_GTHREADS) 41*ec02198aSmrg#include <bits/gthr.h> 42*ec02198aSmrg 43*ec02198aSmrg#include <chrono> // std::chrono::* 44*ec02198aSmrg#include <memory> // std::unique_ptr 45*ec02198aSmrg#include <tuple> // std::tuple 46*ec02198aSmrg 47*ec02198aSmrg#if __cplusplus > 201703L 48*ec02198aSmrg# include <compare> // std::strong_ordering 49*ec02198aSmrg# include <stop_token> // std::stop_source, std::stop_token, std::nostopstate 50*ec02198aSmrg#endif 51*ec02198aSmrg 52*ec02198aSmrg#ifdef _GLIBCXX_USE_NANOSLEEP 53*ec02198aSmrg# include <cerrno> // errno, EINTR 54*ec02198aSmrg# include <time.h> // nanosleep 55*ec02198aSmrg#endif 56*ec02198aSmrg 57*ec02198aSmrg#include <bits/functional_hash.h> // std::hash 58*ec02198aSmrg#include <bits/invoke.h> // std::__invoke 5910d565efSmrg 6010d565efSmrgnamespace std _GLIBCXX_VISIBILITY(default) 6110d565efSmrg{ 6210d565efSmrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 6310d565efSmrg 6410d565efSmrg /** 6510d565efSmrg * @defgroup threads Threads 6610d565efSmrg * @ingroup concurrency 6710d565efSmrg * 6810d565efSmrg * Classes for thread support. 6910d565efSmrg * @{ 7010d565efSmrg */ 7110d565efSmrg 7210d565efSmrg /// thread 7310d565efSmrg class thread 7410d565efSmrg { 7510d565efSmrg public: 7610d565efSmrg // Abstract base class for types that wrap arbitrary functors to be 7710d565efSmrg // invoked in the new thread of execution. 7810d565efSmrg struct _State 7910d565efSmrg { 8010d565efSmrg virtual ~_State(); 8110d565efSmrg virtual void _M_run() = 0; 8210d565efSmrg }; 8310d565efSmrg using _State_ptr = unique_ptr<_State>; 8410d565efSmrg 8510d565efSmrg typedef __gthread_t native_handle_type; 8610d565efSmrg 8710d565efSmrg /// thread::id 8810d565efSmrg class id 8910d565efSmrg { 9010d565efSmrg native_handle_type _M_thread; 9110d565efSmrg 9210d565efSmrg public: 9310d565efSmrg id() noexcept : _M_thread() { } 9410d565efSmrg 9510d565efSmrg explicit 9610d565efSmrg id(native_handle_type __id) : _M_thread(__id) { } 9710d565efSmrg 9810d565efSmrg private: 9910d565efSmrg friend class thread; 100*ec02198aSmrg friend class hash<id>; 10110d565efSmrg 10210d565efSmrg friend bool 103*ec02198aSmrg operator==(id __x, id __y) noexcept; 10410d565efSmrg 105*ec02198aSmrg#if __cpp_lib_three_way_comparison 106*ec02198aSmrg friend strong_ordering 107*ec02198aSmrg operator<=>(id __x, id __y) noexcept; 108*ec02198aSmrg#else 10910d565efSmrg friend bool 110*ec02198aSmrg operator<(id __x, id __y) noexcept; 111*ec02198aSmrg#endif 11210d565efSmrg 11310d565efSmrg template<class _CharT, class _Traits> 11410d565efSmrg friend basic_ostream<_CharT, _Traits>& 115*ec02198aSmrg operator<<(basic_ostream<_CharT, _Traits>& __out, id __id); 11610d565efSmrg }; 11710d565efSmrg 11810d565efSmrg private: 11910d565efSmrg id _M_id; 12010d565efSmrg 12110d565efSmrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 12210d565efSmrg // 2097. packaged_task constructors should be constrained 1230fc04c29Smrg // 3039. Unnecessary decay in thread and packaged_task 124c7a68eb7Smrg template<typename _Tp> 1250fc04c29Smrg using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>; 12610d565efSmrg 127c7a68eb7Smrg public: 128c7a68eb7Smrg thread() noexcept = default; 12910d565efSmrg 130c7a68eb7Smrg template<typename _Callable, typename... _Args, 131c7a68eb7Smrg typename = _Require<__not_same<_Callable>>> 13210d565efSmrg explicit 13310d565efSmrg thread(_Callable&& __f, _Args&&... __args) 13410d565efSmrg { 135c7a68eb7Smrg static_assert( __is_invocable<typename decay<_Callable>::type, 136c7a68eb7Smrg typename decay<_Args>::type...>::value, 137c7a68eb7Smrg "std::thread arguments must be invocable after conversion to rvalues" 138c7a68eb7Smrg ); 139c7a68eb7Smrg 14010d565efSmrg#ifdef GTHR_ACTIVE_PROXY 14110d565efSmrg // Create a reference to pthread_create, not just the gthr weak symbol. 14210d565efSmrg auto __depend = reinterpret_cast<void(*)()>(&pthread_create); 14310d565efSmrg#else 14410d565efSmrg auto __depend = nullptr; 14510d565efSmrg#endif 146*ec02198aSmrg // A call wrapper holding tuple{DECAY_COPY(__f), DECAY_COPY(__args)...} 147*ec02198aSmrg using _Invoker_type = _Invoker<__decayed_tuple<_Callable, _Args...>>; 148*ec02198aSmrg 149*ec02198aSmrg _M_start_thread(_S_make_state<_Invoker_type>( 150*ec02198aSmrg std::forward<_Callable>(__f), std::forward<_Args>(__args)...), 15110d565efSmrg __depend); 15210d565efSmrg } 15310d565efSmrg 15410d565efSmrg ~thread() 15510d565efSmrg { 15610d565efSmrg if (joinable()) 15710d565efSmrg std::terminate(); 15810d565efSmrg } 15910d565efSmrg 160c7a68eb7Smrg thread(const thread&) = delete; 161c7a68eb7Smrg 162c7a68eb7Smrg thread(thread&& __t) noexcept 163c7a68eb7Smrg { swap(__t); } 164c7a68eb7Smrg 16510d565efSmrg thread& operator=(const thread&) = delete; 16610d565efSmrg 16710d565efSmrg thread& operator=(thread&& __t) noexcept 16810d565efSmrg { 16910d565efSmrg if (joinable()) 17010d565efSmrg std::terminate(); 17110d565efSmrg swap(__t); 17210d565efSmrg return *this; 17310d565efSmrg } 17410d565efSmrg 17510d565efSmrg void 17610d565efSmrg swap(thread& __t) noexcept 17710d565efSmrg { std::swap(_M_id, __t._M_id); } 17810d565efSmrg 17910d565efSmrg bool 18010d565efSmrg joinable() const noexcept 18110d565efSmrg { return !(_M_id == id()); } 18210d565efSmrg 18310d565efSmrg void 18410d565efSmrg join(); 18510d565efSmrg 18610d565efSmrg void 18710d565efSmrg detach(); 18810d565efSmrg 189*ec02198aSmrg id 19010d565efSmrg get_id() const noexcept 19110d565efSmrg { return _M_id; } 19210d565efSmrg 19310d565efSmrg /** @pre thread is joinable 19410d565efSmrg */ 19510d565efSmrg native_handle_type 19610d565efSmrg native_handle() 19710d565efSmrg { return _M_id._M_thread; } 19810d565efSmrg 19910d565efSmrg // Returns a value that hints at the number of hardware thread contexts. 20010d565efSmrg static unsigned int 20110d565efSmrg hardware_concurrency() noexcept; 20210d565efSmrg 20310d565efSmrg private: 20410d565efSmrg template<typename _Callable> 20510d565efSmrg struct _State_impl : public _State 20610d565efSmrg { 20710d565efSmrg _Callable _M_func; 20810d565efSmrg 209*ec02198aSmrg template<typename... _Args> 210*ec02198aSmrg _State_impl(_Args&&... __args) 211*ec02198aSmrg : _M_func{{std::forward<_Args>(__args)...}} 21210d565efSmrg { } 21310d565efSmrg 21410d565efSmrg void 21510d565efSmrg _M_run() { _M_func(); } 21610d565efSmrg }; 21710d565efSmrg 21810d565efSmrg void 21910d565efSmrg _M_start_thread(_State_ptr, void (*)()); 22010d565efSmrg 221*ec02198aSmrg template<typename _Callable, typename... _Args> 22210d565efSmrg static _State_ptr 223*ec02198aSmrg _S_make_state(_Args&&... __args) 22410d565efSmrg { 22510d565efSmrg using _Impl = _State_impl<_Callable>; 226*ec02198aSmrg return _State_ptr{new _Impl{std::forward<_Args>(__args)...}}; 22710d565efSmrg } 22810d565efSmrg#if _GLIBCXX_THREAD_ABI_COMPAT 22910d565efSmrg public: 23010d565efSmrg struct _Impl_base; 23110d565efSmrg typedef shared_ptr<_Impl_base> __shared_base_type; 23210d565efSmrg struct _Impl_base 23310d565efSmrg { 23410d565efSmrg __shared_base_type _M_this_ptr; 23510d565efSmrg virtual ~_Impl_base() = default; 23610d565efSmrg virtual void _M_run() = 0; 23710d565efSmrg }; 23810d565efSmrg 23910d565efSmrg private: 24010d565efSmrg void 24110d565efSmrg _M_start_thread(__shared_base_type, void (*)()); 24210d565efSmrg 24310d565efSmrg void 24410d565efSmrg _M_start_thread(__shared_base_type); 24510d565efSmrg#endif 24610d565efSmrg 24710d565efSmrg private: 24810d565efSmrg // A call wrapper that does INVOKE(forwarded tuple elements...) 24910d565efSmrg template<typename _Tuple> 25010d565efSmrg struct _Invoker 25110d565efSmrg { 25210d565efSmrg _Tuple _M_t; 25310d565efSmrg 2540fc04c29Smrg template<typename> 2550fc04c29Smrg struct __result; 2560fc04c29Smrg template<typename _Fn, typename... _Args> 2570fc04c29Smrg struct __result<tuple<_Fn, _Args...>> 2580fc04c29Smrg : __invoke_result<_Fn, _Args...> 2590fc04c29Smrg { }; 26010d565efSmrg 26110d565efSmrg template<size_t... _Ind> 2620fc04c29Smrg typename __result<_Tuple>::type 26310d565efSmrg _M_invoke(_Index_tuple<_Ind...>) 26410d565efSmrg { return std::__invoke(std::get<_Ind>(std::move(_M_t))...); } 26510d565efSmrg 2660fc04c29Smrg typename __result<_Tuple>::type 2670fc04c29Smrg operator()() 2680fc04c29Smrg { 26910d565efSmrg using _Indices 27010d565efSmrg = typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type; 2710fc04c29Smrg return _M_invoke(_Indices()); 2720fc04c29Smrg } 27310d565efSmrg }; 27410d565efSmrg 27510d565efSmrg template<typename... _Tp> 2760fc04c29Smrg using __decayed_tuple = tuple<typename decay<_Tp>::type...>; 27710d565efSmrg 27810d565efSmrg public: 27910d565efSmrg // Returns a call wrapper that stores 28010d565efSmrg // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}. 28110d565efSmrg template<typename _Callable, typename... _Args> 28210d565efSmrg static _Invoker<__decayed_tuple<_Callable, _Args...>> 28310d565efSmrg __make_invoker(_Callable&& __callable, _Args&&... __args) 28410d565efSmrg { 28510d565efSmrg return { __decayed_tuple<_Callable, _Args...>{ 28610d565efSmrg std::forward<_Callable>(__callable), std::forward<_Args>(__args)... 28710d565efSmrg } }; 28810d565efSmrg } 28910d565efSmrg }; 29010d565efSmrg 29110d565efSmrg inline void 29210d565efSmrg swap(thread& __x, thread& __y) noexcept 29310d565efSmrg { __x.swap(__y); } 29410d565efSmrg 29510d565efSmrg inline bool 29610d565efSmrg operator==(thread::id __x, thread::id __y) noexcept 29710d565efSmrg { 29810d565efSmrg // pthread_equal is undefined if either thread ID is not valid, so we 29910d565efSmrg // can't safely use __gthread_equal on default-constructed values (nor 30010d565efSmrg // the non-zero value returned by this_thread::get_id() for 30110d565efSmrg // single-threaded programs using GNU libc). Assume EqualityComparable. 30210d565efSmrg return __x._M_thread == __y._M_thread; 30310d565efSmrg } 30410d565efSmrg 305*ec02198aSmrg#if __cpp_lib_three_way_comparison 306*ec02198aSmrg inline strong_ordering 307*ec02198aSmrg operator<=>(thread::id __x, thread::id __y) noexcept 308*ec02198aSmrg { return __x._M_thread <=> __y._M_thread; } 309*ec02198aSmrg#else 31010d565efSmrg inline bool 31110d565efSmrg operator!=(thread::id __x, thread::id __y) noexcept 31210d565efSmrg { return !(__x == __y); } 31310d565efSmrg 31410d565efSmrg inline bool 31510d565efSmrg operator<(thread::id __x, thread::id __y) noexcept 31610d565efSmrg { 31710d565efSmrg // Pthreads doesn't define any way to do this, so we just have to 31810d565efSmrg // assume native_handle_type is LessThanComparable. 31910d565efSmrg return __x._M_thread < __y._M_thread; 32010d565efSmrg } 32110d565efSmrg 32210d565efSmrg inline bool 32310d565efSmrg operator<=(thread::id __x, thread::id __y) noexcept 32410d565efSmrg { return !(__y < __x); } 32510d565efSmrg 32610d565efSmrg inline bool 32710d565efSmrg operator>(thread::id __x, thread::id __y) noexcept 32810d565efSmrg { return __y < __x; } 32910d565efSmrg 33010d565efSmrg inline bool 33110d565efSmrg operator>=(thread::id __x, thread::id __y) noexcept 33210d565efSmrg { return !(__x < __y); } 333*ec02198aSmrg#endif // __cpp_lib_three_way_comparison 33410d565efSmrg 33510d565efSmrg // DR 889. 33610d565efSmrg /// std::hash specialization for thread::id. 33710d565efSmrg template<> 33810d565efSmrg struct hash<thread::id> 33910d565efSmrg : public __hash_base<size_t, thread::id> 34010d565efSmrg { 34110d565efSmrg size_t 34210d565efSmrg operator()(const thread::id& __id) const noexcept 34310d565efSmrg { return std::_Hash_impl::hash(__id._M_thread); } 34410d565efSmrg }; 34510d565efSmrg 34610d565efSmrg template<class _CharT, class _Traits> 34710d565efSmrg inline basic_ostream<_CharT, _Traits>& 34810d565efSmrg operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id) 34910d565efSmrg { 35010d565efSmrg if (__id == thread::id()) 35110d565efSmrg return __out << "thread::id of a non-executing thread"; 35210d565efSmrg else 35310d565efSmrg return __out << __id._M_thread; 35410d565efSmrg } 35510d565efSmrg 35610d565efSmrg /** @namespace std::this_thread 357*ec02198aSmrg * @brief ISO C++ 2011 namespace for interacting with the current thread 358*ec02198aSmrg * 359*ec02198aSmrg * C++11 30.3.2 [thread.thread.this] Namespace this_thread. 36010d565efSmrg */ 36110d565efSmrg namespace this_thread 36210d565efSmrg { 36310d565efSmrg /// get_id 36410d565efSmrg inline thread::id 36510d565efSmrg get_id() noexcept 36610d565efSmrg { 367*ec02198aSmrg#ifdef _GLIBCXX_NATIVE_THREAD_ID 368*ec02198aSmrg return thread::id(_GLIBCXX_NATIVE_THREAD_ID); 369*ec02198aSmrg#else 37010d565efSmrg return thread::id(__gthread_self()); 371*ec02198aSmrg#endif 37210d565efSmrg } 37310d565efSmrg 37410d565efSmrg /// yield 37510d565efSmrg inline void 37610d565efSmrg yield() noexcept 37710d565efSmrg { 37810d565efSmrg#ifdef _GLIBCXX_USE_SCHED_YIELD 37910d565efSmrg __gthread_yield(); 38010d565efSmrg#endif 38110d565efSmrg } 38210d565efSmrg 38310d565efSmrg void 38410d565efSmrg __sleep_for(chrono::seconds, chrono::nanoseconds); 38510d565efSmrg 38610d565efSmrg /// sleep_for 38710d565efSmrg template<typename _Rep, typename _Period> 38810d565efSmrg inline void 38910d565efSmrg sleep_for(const chrono::duration<_Rep, _Period>& __rtime) 39010d565efSmrg { 39110d565efSmrg if (__rtime <= __rtime.zero()) 39210d565efSmrg return; 39310d565efSmrg auto __s = chrono::duration_cast<chrono::seconds>(__rtime); 39410d565efSmrg auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s); 39510d565efSmrg#ifdef _GLIBCXX_USE_NANOSLEEP 39610d565efSmrg __gthread_time_t __ts = 39710d565efSmrg { 39810d565efSmrg static_cast<std::time_t>(__s.count()), 39910d565efSmrg static_cast<long>(__ns.count()) 40010d565efSmrg }; 40110d565efSmrg while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) 40210d565efSmrg { } 40310d565efSmrg#else 40410d565efSmrg __sleep_for(__s, __ns); 40510d565efSmrg#endif 40610d565efSmrg } 40710d565efSmrg 40810d565efSmrg /// sleep_until 40910d565efSmrg template<typename _Clock, typename _Duration> 41010d565efSmrg inline void 41110d565efSmrg sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) 41210d565efSmrg { 413*ec02198aSmrg#if __cplusplus > 201703L 414*ec02198aSmrg static_assert(chrono::is_clock_v<_Clock>); 415*ec02198aSmrg#endif 41610d565efSmrg auto __now = _Clock::now(); 41710d565efSmrg if (_Clock::is_steady) 41810d565efSmrg { 41910d565efSmrg if (__now < __atime) 42010d565efSmrg sleep_for(__atime - __now); 42110d565efSmrg return; 42210d565efSmrg } 42310d565efSmrg while (__now < __atime) 42410d565efSmrg { 42510d565efSmrg sleep_for(__atime - __now); 42610d565efSmrg __now = _Clock::now(); 42710d565efSmrg } 42810d565efSmrg } 42910d565efSmrg } 43010d565efSmrg 431*ec02198aSmrg /// @} group threads 43210d565efSmrg 433*ec02198aSmrg#ifdef __cpp_lib_jthread 434*ec02198aSmrg 435*ec02198aSmrg class jthread 436*ec02198aSmrg { 437*ec02198aSmrg public: 438*ec02198aSmrg using id = thread::id; 439*ec02198aSmrg using native_handle_type = thread::native_handle_type; 440*ec02198aSmrg 441*ec02198aSmrg jthread() noexcept 442*ec02198aSmrg : _M_stop_source{nostopstate} 443*ec02198aSmrg { } 444*ec02198aSmrg 445*ec02198aSmrg template<typename _Callable, typename... _Args, 446*ec02198aSmrg typename = enable_if_t<!is_same_v<remove_cvref_t<_Callable>, 447*ec02198aSmrg jthread>>> 448*ec02198aSmrg explicit 449*ec02198aSmrg jthread(_Callable&& __f, _Args&&... __args) 450*ec02198aSmrg : _M_thread{_S_create(_M_stop_source, std::forward<_Callable>(__f), 451*ec02198aSmrg std::forward<_Args>(__args)...)} 452*ec02198aSmrg { } 453*ec02198aSmrg 454*ec02198aSmrg jthread(const jthread&) = delete; 455*ec02198aSmrg jthread(jthread&&) noexcept = default; 456*ec02198aSmrg 457*ec02198aSmrg ~jthread() 458*ec02198aSmrg { 459*ec02198aSmrg if (joinable()) 460*ec02198aSmrg { 461*ec02198aSmrg request_stop(); 462*ec02198aSmrg join(); 463*ec02198aSmrg } 464*ec02198aSmrg } 465*ec02198aSmrg 466*ec02198aSmrg jthread& 467*ec02198aSmrg operator=(const jthread&) = delete; 468*ec02198aSmrg 469*ec02198aSmrg jthread& 470*ec02198aSmrg operator=(jthread&& __other) noexcept 471*ec02198aSmrg { 472*ec02198aSmrg std::jthread(std::move(__other)).swap(*this); 473*ec02198aSmrg return *this; 474*ec02198aSmrg } 475*ec02198aSmrg 476*ec02198aSmrg void 477*ec02198aSmrg swap(jthread& __other) noexcept 478*ec02198aSmrg { 479*ec02198aSmrg std::swap(_M_stop_source, __other._M_stop_source); 480*ec02198aSmrg std::swap(_M_thread, __other._M_thread); 481*ec02198aSmrg } 482*ec02198aSmrg 483*ec02198aSmrg [[nodiscard]] bool 484*ec02198aSmrg joinable() const noexcept 485*ec02198aSmrg { 486*ec02198aSmrg return _M_thread.joinable(); 487*ec02198aSmrg } 488*ec02198aSmrg 489*ec02198aSmrg void 490*ec02198aSmrg join() 491*ec02198aSmrg { 492*ec02198aSmrg _M_thread.join(); 493*ec02198aSmrg } 494*ec02198aSmrg 495*ec02198aSmrg void 496*ec02198aSmrg detach() 497*ec02198aSmrg { 498*ec02198aSmrg _M_thread.detach(); 499*ec02198aSmrg } 500*ec02198aSmrg 501*ec02198aSmrg [[nodiscard]] id 502*ec02198aSmrg get_id() const noexcept 503*ec02198aSmrg { 504*ec02198aSmrg return _M_thread.get_id(); 505*ec02198aSmrg } 506*ec02198aSmrg 507*ec02198aSmrg [[nodiscard]] native_handle_type 508*ec02198aSmrg native_handle() 509*ec02198aSmrg { 510*ec02198aSmrg return _M_thread.native_handle(); 511*ec02198aSmrg } 512*ec02198aSmrg 513*ec02198aSmrg [[nodiscard]] static unsigned 514*ec02198aSmrg hardware_concurrency() noexcept 515*ec02198aSmrg { 516*ec02198aSmrg return thread::hardware_concurrency(); 517*ec02198aSmrg } 518*ec02198aSmrg 519*ec02198aSmrg [[nodiscard]] stop_source 520*ec02198aSmrg get_stop_source() noexcept 521*ec02198aSmrg { 522*ec02198aSmrg return _M_stop_source; 523*ec02198aSmrg } 524*ec02198aSmrg 525*ec02198aSmrg [[nodiscard]] stop_token 526*ec02198aSmrg get_stop_token() const noexcept 527*ec02198aSmrg { 528*ec02198aSmrg return _M_stop_source.get_token(); 529*ec02198aSmrg } 530*ec02198aSmrg 531*ec02198aSmrg bool request_stop() noexcept 532*ec02198aSmrg { 533*ec02198aSmrg return _M_stop_source.request_stop(); 534*ec02198aSmrg } 535*ec02198aSmrg 536*ec02198aSmrg friend void swap(jthread& __lhs, jthread& __rhs) noexcept 537*ec02198aSmrg { 538*ec02198aSmrg __lhs.swap(__rhs); 539*ec02198aSmrg } 540*ec02198aSmrg 541*ec02198aSmrg private: 542*ec02198aSmrg template<typename _Callable, typename... _Args> 543*ec02198aSmrg static thread 544*ec02198aSmrg _S_create(stop_source& __ssrc, _Callable&& __f, _Args&&... __args) 545*ec02198aSmrg { 546*ec02198aSmrg if constexpr(is_invocable_v<decay_t<_Callable>, stop_token, 547*ec02198aSmrg decay_t<_Args>...>) 548*ec02198aSmrg return thread{std::forward<_Callable>(__f), __ssrc.get_token(), 549*ec02198aSmrg std::forward<_Args>(__args)...}; 550*ec02198aSmrg else 551*ec02198aSmrg { 552*ec02198aSmrg static_assert(is_invocable_v<decay_t<_Callable>, 553*ec02198aSmrg decay_t<_Args>...>, 554*ec02198aSmrg "std::thread arguments must be invocable after" 555*ec02198aSmrg " conversion to rvalues"); 556*ec02198aSmrg return thread{std::forward<_Callable>(__f), 557*ec02198aSmrg std::forward<_Args>(__args)...}; 558*ec02198aSmrg } 559*ec02198aSmrg } 560*ec02198aSmrg 561*ec02198aSmrg stop_source _M_stop_source; 562*ec02198aSmrg thread _M_thread; 563*ec02198aSmrg }; 564*ec02198aSmrg#endif // __cpp_lib_jthread 565c7a68eb7Smrg_GLIBCXX_END_NAMESPACE_VERSION 56610d565efSmrg} // namespace 5670fc04c29Smrg#endif // _GLIBCXX_HAS_GTHREADS 56810d565efSmrg#endif // C++11 56910d565efSmrg#endif // _GLIBCXX_THREAD 570