1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: no-threads
10 // UNSUPPORTED: c++03, c++11, c++14, c++17
11 // XFAIL: availability-synchronization_library-missing
13 // template<class F, class... Args>
14 // explicit jthread(F&& f, Args&&... args);
19 #include <type_traits>
22 #include "test_macros.h"
24 template <class... Args
>
26 void operator()(Args
...) const;
29 // Constraints: remove_cvref_t<F> is not the same type as jthread.
30 static_assert(std::is_constructible_v
<std::jthread
, Func
<>>);
31 static_assert(std::is_constructible_v
<std::jthread
, Func
<int>, int>);
32 static_assert(!std::is_constructible_v
<std::jthread
, std::jthread
const&>);
36 void conversion_test(T
);
38 template <class T
, class... Args
>
39 concept ImplicitlyConstructible
= requires(Args
&&... args
) { conversion_test
<T
>({std::forward
<Args
>(args
)...}); };
41 static_assert(!ImplicitlyConstructible
<std::jthread
, Func
<>>);
42 static_assert(!ImplicitlyConstructible
<std::jthread
, Func
<int>, int>);
44 int main(int, char**) {
45 // Effects: Initializes ssource
46 // Postconditions: get_id() != id() is true and ssource.stop_possible() is true
47 // and *this represents the newly started thread.
49 std::jthread jt
{[] {}};
50 assert(jt
.get_stop_source().stop_possible());
51 assert(jt
.get_id() != std::jthread::id());
54 // The new thread of execution executes
55 // invoke(auto(std::forward<F>(f)), get_stop_token(), auto(std::forward<Args>(args))...)
56 // if that expression is well-formed,
59 std::jthread jt
{[&result
](std::stop_token st
, int i
) {
60 assert(st
.stop_possible());
61 assert(!st
.stop_requested());
70 // invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)
73 std::jthread jt
{[&result
](int i
) { result
+= i
; }, 5};
78 // with the values produced by auto being materialized ([conv.rval]) in the constructing thread.
81 std::jthread::id threadId
;
82 bool copyConstructed
= false;
83 bool moveConstructed
= false;
85 TrackThread() : threadId(std::this_thread::get_id()) {}
86 TrackThread(const TrackThread
&) : threadId(std::this_thread::get_id()), copyConstructed(true) {}
87 TrackThread(TrackThread
&&) : threadId(std::this_thread::get_id()), moveConstructed(true) {}
90 auto mainThread
= std::this_thread::get_id();
93 std::jthread jt1
{[mainThread
](const TrackThread
& arg
) {
94 assert(arg
.threadId
== mainThread
);
95 assert(arg
.threadId
!= std::this_thread::get_id());
96 assert(arg
.copyConstructed
);
101 std::jthread jt2
{[mainThread
](const TrackThread
& arg
) {
102 assert(arg
.threadId
== mainThread
);
103 assert(arg
.threadId
!= std::this_thread::get_id());
104 assert(arg
.moveConstructed
);
109 #if !defined(TEST_HAS_NO_EXCEPTIONS)
110 // [Note 1: This implies that any exceptions not thrown from the invocation of the copy
111 // of f will be thrown in the constructing thread, not the new thread. - end note]
114 std::jthread::id threadId
;
116 struct ThrowOnCopyFunc
{
117 ThrowOnCopyFunc() = default;
118 ThrowOnCopyFunc(const ThrowOnCopyFunc
&) { throw Exception
{std::this_thread::get_id()}; }
119 void operator()() const {}
125 } catch (const Exception
& e
) {
126 assert(e
.threadId
== std::this_thread::get_id());
129 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
131 // Synchronization: The completion of the invocation of the constructor
132 // synchronizes with the beginning of the invocation of the copy of f.
137 Arg(int& f
) : flag_(f
) {}
139 Arg(const Arg
& other
) : flag_(other
.flag_
) { flag_
= 5; }
144 [&flag
](const auto&) {
145 assert(flag
== 5); // happens-after the copy-construction of arg
150 // Per https://eel.is/c++draft/thread.jthread.class#thread.jthread.cons-8:
152 // Throws: system_error if unable to start the new thread.
154 // resource_unavailable_try_again - the system lacked the necessary resources to create another thread,
155 // or the system-imposed limit on the number of threads in a process would be exceeded.
157 // Unfortunately, this is extremely hard to test portably so we don't have a test for this error condition right now.