1 // Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
18 // { dg-do run { target c++20 } }
19 // { dg-add-options libatomic }
20 // { dg-additional-options "-pthread" { target pthread } }
21 // { dg-require-gthreads "" }
26 #include <testsuite_hooks.h>
28 using namespace std::literals
;
30 //------------------------------------------------------
32 void test_no_stop_token()
34 // test the basic jthread API (not taking stop_token arg)
36 VERIFY(std::jthread::hardware_concurrency() == std::thread::hardware_concurrency());
37 std::stop_token stoken
;
38 VERIFY(!stoken
.stop_possible());
40 std::jthread::id t1ID
{std::this_thread::get_id()};
41 std::atomic
<bool> t1AllSet
{false};
42 std::jthread
t1([&t1ID
, &t1AllSet
] {
43 t1ID
= std::this_thread::get_id();
45 for (int c
='9'; c
>='0'; --c
) {
46 std::this_thread::sleep_for(222ms
);
49 for (int i
=0; !t1AllSet
.load(); ++i
) {
50 std::this_thread::sleep_for(10ms
);
52 VERIFY(t1
.joinable());
53 VERIFY(t1ID
== t1
.get_id());
54 stoken
= t1
.get_stop_token();
55 VERIFY(!stoken
.stop_requested());
57 VERIFY(stoken
.stop_requested());
60 //------------------------------------------------------
62 void test_stop_token()
64 // test the basic thread API (taking stop_token arg)
66 std::stop_source ssource
;
67 std::stop_source origsource
;
68 VERIFY(ssource
.stop_possible());
69 VERIFY(!ssource
.stop_requested());
71 std::jthread::id t1ID
{std::this_thread::get_id()};
72 std::atomic
<bool> t1AllSet
{false};
73 std::atomic
<bool> t1done
{false};
74 std::jthread
t1([&t1ID
, &t1AllSet
, &t1done
] (std::stop_token st
) {
75 // check some values of the started thread:
76 t1ID
= std::this_thread::get_id();
78 for (int i
=0; !st
.stop_requested(); ++i
) {
79 std::this_thread::sleep_for(100ms
);
84 for (int i
=0; !t1AllSet
.load(); ++i
) {
85 std::this_thread::sleep_for(10ms
);
87 // and check all values:
88 VERIFY(t1
.joinable());
89 VERIFY(t1ID
== t1
.get_id());
91 std::this_thread::sleep_for(470ms
);
92 origsource
= std::move(ssource
);
93 ssource
= t1
.get_stop_source();
94 VERIFY(!ssource
.stop_requested());
95 auto ret
= ssource
.request_stop();
97 ret
= ssource
.request_stop();
99 VERIFY(ssource
.stop_requested());
100 VERIFY(!t1done
.load());
101 VERIFY(!origsource
.stop_requested());
103 std::this_thread::sleep_for(470ms
);
104 origsource
.request_stop();
106 VERIFY(origsource
.stop_requested());
107 VERIFY(ssource
.stop_requested());
110 //------------------------------------------------------
114 std::stop_source ssource
;
115 VERIFY(ssource
.stop_possible());
117 std::jthread
t1([](std::stop_token stoken
) {
118 for (int i
=0; !stoken
.stop_requested(); ++i
) {
119 std::this_thread::sleep_for(100ms
);
122 ssource
= t1
.get_stop_source();
123 std::jthread
t2([ssource
] () mutable {
124 for (int i
=0; i
< 10; ++i
) {
125 std::this_thread::sleep_for(70ms
);
127 ssource
.request_stop();
129 // wait for all thread to finish:
131 VERIFY(!t2
.joinable());
132 VERIFY(t1
.joinable());
134 VERIFY(!t1
.joinable());
138 //------------------------------------------------------
142 std::stop_source ssource
;
143 VERIFY(ssource
.stop_possible());
144 std::atomic
<bool> t1FinallyInterrupted
{false};
147 std::jthread::id t1ID
{std::this_thread::get_id()};
148 bool t1IsInterrupted
;
149 std::stop_token t1InterruptToken
;
150 std::atomic
<bool> t1AllSet
{false};
151 std::jthread
t1([&t1ID
, &t1IsInterrupted
, &t1InterruptToken
, &t1AllSet
, &t1FinallyInterrupted
]
152 (std::stop_token stoken
) {
153 // check some values of the started thread:
154 t1ID
= std::this_thread::get_id();
155 t1InterruptToken
= stoken
;
156 t1IsInterrupted
= stoken
.stop_requested();
157 VERIFY(stoken
.stop_possible());
158 VERIFY(!stoken
.stop_requested());
159 t1AllSet
.store(true);
160 for (int i
=0; !stoken
.stop_requested(); ++i
) {
161 std::this_thread::sleep_for(100ms
);
163 t1FinallyInterrupted
.store(true);
165 for (int i
=0; !t1AllSet
.load(); ++i
) {
166 std::this_thread::sleep_for(10ms
);
168 VERIFY(!t0
.joinable());
169 VERIFY(t1
.joinable());
170 VERIFY(t1ID
== t1
.get_id());
171 VERIFY(t1IsInterrupted
== false);
172 VERIFY(t1InterruptToken
== t1
.get_stop_source().get_token());
173 ssource
= t1
.get_stop_source();
174 VERIFY(t1InterruptToken
.stop_possible());
175 VERIFY(!t1InterruptToken
.stop_requested());
177 VERIFY(!t1
.joinable());
180 VERIFY(!t1FinallyInterrupted
.load());
181 ssource
.request_stop();
182 VERIFY(ssource
.stop_requested());
183 for (int i
=0; !t1FinallyInterrupted
.load() && i
< 100; ++i
) {
184 std::this_thread::sleep_for(100ms
);
186 VERIFY(t1FinallyInterrupted
.load());
189 //------------------------------------------------------
191 void test_move_assignment()
193 std::jthread
thread1([]{});
194 std::jthread
thread2([]{});
196 const auto id2
= thread2
.get_id();
197 const auto ssource2
= thread2
.get_stop_source();
199 thread1
= std::move(thread2
);
201 VERIFY(thread1
.get_id() == id2
);
202 VERIFY(thread2
.get_id() == std::jthread::id());
204 VERIFY(thread1
.get_stop_source() == ssource2
);
205 VERIFY(!thread2
.get_stop_source().stop_possible());
210 std::set_terminate([](){
214 test_no_stop_token();
218 test_move_assignment();