xref: /llvm-project/libcxx/include/__thread/jthread.h (revision c6f3b7bcd0596d30f8dabecdfb9e44f9a07b6e4c)
1695138caSHui // -*- C++ -*-
2695138caSHui //===----------------------------------------------------------------------===//
3695138caSHui //
4695138caSHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5695138caSHui // See https://llvm.org/LICENSE.txt for license information.
6695138caSHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7695138caSHui //
8695138caSHui //===----------------------------------------------------------------------===//
9695138caSHui 
10695138caSHui #ifndef _LIBCPP___THREAD_JTHREAD_H
11695138caSHui #define _LIBCPP___THREAD_JTHREAD_H
12695138caSHui 
13695138caSHui #include <__config>
14695138caSHui #include <__stop_token/stop_source.h>
15695138caSHui #include <__stop_token/stop_token.h>
1609e3a360SLouis Dionne #include <__thread/id.h>
177162fd75SLouis Dionne #include <__thread/support.h>
18695138caSHui #include <__thread/thread.h>
19695138caSHui #include <__type_traits/decay.h>
2009e3a360SLouis Dionne #include <__type_traits/invoke.h>
21695138caSHui #include <__type_traits/is_constructible.h>
22695138caSHui #include <__type_traits/is_same.h>
23695138caSHui #include <__type_traits/remove_cvref.h>
24695138caSHui #include <__utility/forward.h>
25695138caSHui #include <__utility/move.h>
2609e3a360SLouis Dionne #include <__utility/swap.h>
27695138caSHui 
28695138caSHui #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
29695138caSHui #  pragma GCC system_header
30695138caSHui #endif
31695138caSHui 
327b462251SLouis Dionne _LIBCPP_PUSH_MACROS
337b462251SLouis Dionne #include <__undef_macros>
347b462251SLouis Dionne 
35*c6f3b7bcSNikolas Klauser #if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS
36695138caSHui 
37695138caSHui _LIBCPP_BEGIN_NAMESPACE_STD
38695138caSHui 
39695138caSHui class _LIBCPP_AVAILABILITY_SYNC jthread {
40695138caSHui public:
41695138caSHui   // types
42695138caSHui   using id                 = thread::id;
43695138caSHui   using native_handle_type = thread::native_handle_type;
44695138caSHui 
45695138caSHui   // [thread.jthread.cons], constructors, move, and assignment
46695138caSHui   _LIBCPP_HIDE_FROM_ABI jthread() noexcept : __stop_source_(std::nostopstate) {}
47695138caSHui 
48695138caSHui   template <class _Fun, class... _Args>
49695138caSHui   _LIBCPP_HIDE_FROM_ABI explicit jthread(_Fun&& __fun, _Args&&... __args)
50695138caSHui     requires(!std::is_same_v<remove_cvref_t<_Fun>, jthread>)
51695138caSHui       : __stop_source_(),
52695138caSHui         __thread_(__init_thread(__stop_source_, std::forward<_Fun>(__fun), std::forward<_Args>(__args)...)) {
53695138caSHui     static_assert(is_constructible_v<decay_t<_Fun>, _Fun>);
54695138caSHui     static_assert((is_constructible_v<decay_t<_Args>, _Args> && ...));
55695138caSHui     static_assert(is_invocable_v<decay_t<_Fun>, decay_t<_Args>...> ||
56695138caSHui                   is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>);
57695138caSHui   }
58695138caSHui 
59695138caSHui   _LIBCPP_HIDE_FROM_ABI ~jthread() {
60695138caSHui     if (joinable()) {
61695138caSHui       request_stop();
62695138caSHui       join();
63695138caSHui     }
64695138caSHui   }
65695138caSHui 
66695138caSHui   jthread(const jthread&) = delete;
67695138caSHui 
68695138caSHui   _LIBCPP_HIDE_FROM_ABI jthread(jthread&&) noexcept = default;
69695138caSHui 
70695138caSHui   jthread& operator=(const jthread&) = delete;
71695138caSHui 
72695138caSHui   _LIBCPP_HIDE_FROM_ABI jthread& operator=(jthread&& __other) noexcept {
73695138caSHui     if (this != &__other) {
74695138caSHui       if (joinable()) {
75695138caSHui         request_stop();
76695138caSHui         join();
77695138caSHui       }
78695138caSHui       __stop_source_ = std::move(__other.__stop_source_);
79695138caSHui       __thread_      = std::move(__other.__thread_);
80695138caSHui     }
81695138caSHui 
82695138caSHui     return *this;
83695138caSHui   }
84695138caSHui 
85695138caSHui   // [thread.jthread.mem], members
86695138caSHui   _LIBCPP_HIDE_FROM_ABI void swap(jthread& __other) noexcept {
87695138caSHui     std::swap(__stop_source_, __other.__stop_source_);
88695138caSHui     std::swap(__thread_, __other.__thread_);
89695138caSHui   }
90695138caSHui 
91695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool joinable() const noexcept { return get_id() != id(); }
92695138caSHui 
93695138caSHui   _LIBCPP_HIDE_FROM_ABI void join() { __thread_.join(); }
94695138caSHui 
95695138caSHui   _LIBCPP_HIDE_FROM_ABI void detach() { __thread_.detach(); }
96695138caSHui 
97695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI id get_id() const noexcept { return __thread_.get_id(); }
98695138caSHui 
99695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __thread_.native_handle(); }
100695138caSHui 
101695138caSHui   // [thread.jthread.stop], stop token handling
102695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_source get_stop_source() noexcept { return __stop_source_; }
103695138caSHui 
104695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_token get_stop_token() const noexcept { return __stop_source_.get_token(); }
105695138caSHui 
106695138caSHui   _LIBCPP_HIDE_FROM_ABI bool request_stop() noexcept { return __stop_source_.request_stop(); }
107695138caSHui 
108695138caSHui   // [thread.jthread.special], specialized algorithms
109695138caSHui   _LIBCPP_HIDE_FROM_ABI friend void swap(jthread& __lhs, jthread& __rhs) noexcept { __lhs.swap(__rhs); }
110695138caSHui 
111695138caSHui   // [thread.jthread.static], static members
112695138caSHui   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static unsigned int hardware_concurrency() noexcept {
113695138caSHui     return thread::hardware_concurrency();
114695138caSHui   }
115695138caSHui 
116695138caSHui private:
117695138caSHui   template <class _Fun, class... _Args>
118695138caSHui   _LIBCPP_HIDE_FROM_ABI static thread __init_thread(const stop_source& __ss, _Fun&& __fun, _Args&&... __args) {
119695138caSHui     if constexpr (is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>) {
120695138caSHui       return thread(std::forward<_Fun>(__fun), __ss.get_token(), std::forward<_Args>(__args)...);
121695138caSHui     } else {
122695138caSHui       return thread(std::forward<_Fun>(__fun), std::forward<_Args>(__args)...);
123695138caSHui     }
124695138caSHui   }
125695138caSHui 
126695138caSHui   stop_source __stop_source_;
127695138caSHui   thread __thread_;
128695138caSHui };
129695138caSHui 
130695138caSHui _LIBCPP_END_NAMESPACE_STD
131695138caSHui 
132*c6f3b7bcSNikolas Klauser #endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS
133695138caSHui 
1347b462251SLouis Dionne _LIBCPP_POP_MACROS
1357b462251SLouis Dionne 
136695138caSHui #endif // _LIBCPP___THREAD_JTHREAD_H
137