Commit 74533764 by Jonathan Wakely Committed by Jonathan Wakely

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.

From-SVN: r278364
parent 970a9bfa
2019-11-16 Jonathan Wakely <jwakely@redhat.com>
* 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.
2019-11-15 Edward Smith-Rowland <3dw4rd@verizon.net> 2019-11-15 Edward Smith-Rowland <3dw4rd@verizon.net>
Implement the <tuple> part of C++20 p1032 Misc constexpr bits. Implement the <tuple> part of C++20 p1032 Misc constexpr bits.
......
...@@ -425,31 +425,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -425,31 +425,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using native_handle_type = std::thread::native_handle_type; using native_handle_type = std::thread::native_handle_type;
jthread() noexcept jthread() noexcept
: _M_stop_source{ nostopstate_t{ } } : _M_stop_source{nostopstate}
{ } { }
template<typename _Callable, typename... _Args, template<typename _Callable, typename... _Args,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<_Callable>, jthread>>> typename = enable_if_t<!is_same_v<remove_cvref_t<_Callable>,
explicit jthread>>>
jthread(_Callable&& __f, _Args&&... __args) explicit
: _M_thread{[](stop_token __token, auto&& __cb, auto&&... __args) jthread(_Callable&& __f, _Args&&... __args)
{ : _M_thread{_S_create(_M_stop_source, std::forward<_Callable>(__f),
if constexpr(std::is_invocable_v<_Callable, stop_token, _Args...>) std::forward<_Args>(__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)...}
{ }
jthread(const jthread&) = delete; jthread(const jthread&) = delete;
jthread(jthread&&) noexcept = default; jthread(jthread&&) noexcept = default;
...@@ -476,7 +462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -476,7 +462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::swap(_M_thread, __other._M_thread); std::swap(_M_thread, __other._M_thread);
} }
bool [[nodiscard]] bool
joinable() const noexcept joinable() const noexcept
{ {
return _M_thread.joinable(); return _M_thread.joinable();
...@@ -494,19 +480,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -494,19 +480,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_thread.detach(); _M_thread.detach();
} }
id [[nodiscard]] id
get_id() const noexcept get_id() const noexcept
{ {
_M_thread.get_id(); _M_thread.get_id();
} }
native_handle_type [[nodiscard]] native_handle_type
native_handle() native_handle()
{ {
return _M_thread.native_handle(); return _M_thread.native_handle();
} }
static unsigned [[nodiscard]] static unsigned
hardware_concurrency() noexcept hardware_concurrency() noexcept
{ {
return std::thread::hardware_concurrency(); return std::thread::hardware_concurrency();
...@@ -529,7 +515,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -529,7 +515,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return get_stop_source().request_stop(); return get_stop_source().request_stop();
} }
friend void swap(jthread& __lhs, jthread& __rhs) noexcept
{
__lhs.swap(__rhs);
}
private: 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; stop_source _M_stop_source;
std::thread _M_thread; std::thread _M_thread;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment