This change avoids storing a copy of a stop_token object that isn't needed and won't be passed to the callable object. This slightly reduces memory usage when the callable doesn't use a stop_token. It also removes indirection in the invocation of the callable in the new thread, as there is no lambda and no additional calls to std::invoke.
It also adds some missing [[nodiscard]] attributes, and the non-member swap overload for std::jthread. * include/std/thread (jthread::jthread()): Use nostopstate constant. (jthread::jthread(Callable&&, Args&&...)): Use helper function to create std::thread instead of indirection through a lambda. Use remove_cvref_t instead of decay_t. (jthread::joinable(), jthread::get_id(), jthread::native_handle()) (jthread::hardware_concurrency()): Add nodiscard attribute. (swap(jthread&. jthread&)): Define hidden friend. (jthread::_S_create): New helper function for constructor. Tested powerpc64le-linux, committed to trunk. As discussed with Tom, we also plan to replace the use of shared_ptr in stop_source and stop_token with something more lightweight, that doesn't store a weak count and two copies of the pointer.
commit 650ad104007e2f3474d735ec642b7613886cfcfe Author: Jonathan Wakely <jwak...@redhat.com> Date: Sat Nov 16 21:32:05 2019 +0000 libstdc++: Optimize std::jthread construction This change avoids storing a copy of a stop_token object that isn't needed and won't be passed to the callable object. This slightly reduces memory usage when the callable doesn't use a stop_token. It also removes indirection in the invocation of the callable in the new thread, as there is no lambda and no additional calls to std::invoke. It also adds some missing [[nodiscard]] attributes, and the non-member swap overload for std::jthread. * include/std/thread (jthread::jthread()): Use nostopstate constant. (jthread::jthread(Callable&&, Args&&...)): Use helper function to create std::thread instead of indirection through a lambda. Use remove_cvref_t instead of decay_t. (jthread::joinable(), jthread::get_id(), jthread::native_handle()) (jthread::hardware_concurrency()): Add nodiscard attribute. (swap(jthread&. jthread&)): Define hidden friend. (jthread::_S_create): New helper function for constructor. diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index 93afa766d18..010921b2160 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -425,31 +425,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using native_handle_type = std::thread::native_handle_type; jthread() noexcept - : _M_stop_source{ nostopstate_t{ } } + : _M_stop_source{nostopstate} { } template<typename _Callable, typename... _Args, - typename = std::enable_if_t<!std::is_same_v<std::decay_t<_Callable>, jthread>>> - explicit - jthread(_Callable&& __f, _Args&&... __args) - : _M_thread{[](stop_token __token, auto&& __cb, auto&&... __args) - { - if constexpr(std::is_invocable_v<_Callable, stop_token, _Args...>) - { - std::invoke(std::forward<decltype(__cb)>(__cb), - std::move(__token), - std::forward<decltype(__args)>(__args)...); - } - else - { - std::invoke(std::forward<decltype(__cb)>(__cb), - std::forward<decltype(__args)>(__args)...); - } - }, - _M_stop_source.get_token(), - std::forward<_Callable>(__f), - std::forward<_Args>(__args)...} - { } + typename = enable_if_t<!is_same_v<remove_cvref_t<_Callable>, + jthread>>> + explicit + jthread(_Callable&& __f, _Args&&... __args) + : _M_thread{_S_create(_M_stop_source, std::forward<_Callable>(__f), + std::forward<_Args>(__args)...)} + { } jthread(const jthread&) = delete; jthread(jthread&&) noexcept = default; @@ -476,7 +462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::swap(_M_thread, __other._M_thread); } - bool + [[nodiscard]] bool joinable() const noexcept { return _M_thread.joinable(); @@ -494,19 +480,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_thread.detach(); } - id + [[nodiscard]] id get_id() const noexcept { _M_thread.get_id(); } - native_handle_type + [[nodiscard]] native_handle_type native_handle() { return _M_thread.native_handle(); } - static unsigned + [[nodiscard]] static unsigned hardware_concurrency() noexcept { return std::thread::hardware_concurrency(); @@ -529,7 +515,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return get_stop_source().request_stop(); } + friend void swap(jthread& __lhs, jthread& __rhs) noexcept + { + __lhs.swap(__rhs); + } + private: + template<typename _Callable, typename... _Args> + static thread + _S_create(stop_source& __ssrc, _Callable&& __f, _Args&&... __args) + { + if constexpr(is_invocable_v<_Callable, stop_token, _Args...>) + return thread{std::forward<_Callable>(__f), __ssrc.get_token(), + std::forward<_Args>(__args)...}; + else + return thread{std::forward<_Callable>(__f), + std::forward<_Args>(__args)...}; + } + stop_source _M_stop_source; std::thread _M_thread; };