jthread.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright (C) 2019-2022 Free Software Foundation, Inc.
  2. //
  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)
  7. // any later version.
  8. // This library is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. // You should have received a copy of the GNU General Public License along
  13. // with this library; see the file COPYING3. If not see
  14. // <http://www.gnu.org/licenses/>.
  15. // { dg-options "-std=gnu++2a -pthread" }
  16. // { dg-do run { target c++2a } }
  17. // { dg-add-options libatomic }
  18. // { dg-additional-options "-pthread" { target pthread } }
  19. // { dg-require-gthreads "" }
  20. #include <thread>
  21. #include <chrono>
  22. #include <atomic>
  23. #include <testsuite_hooks.h>
  24. using namespace std::literals;
  25. //------------------------------------------------------
  26. void test_no_stop_token()
  27. {
  28. // test the basic jthread API (not taking stop_token arg)
  29. VERIFY(std::jthread::hardware_concurrency() == std::thread::hardware_concurrency());
  30. std::stop_token stoken;
  31. VERIFY(!stoken.stop_possible());
  32. {
  33. std::jthread::id t1ID{std::this_thread::get_id()};
  34. std::atomic<bool> t1AllSet{false};
  35. std::jthread t1([&t1ID, &t1AllSet] {
  36. t1ID = std::this_thread::get_id();
  37. t1AllSet.store(true);
  38. for (int c='9'; c>='0'; --c) {
  39. std::this_thread::sleep_for(222ms);
  40. }
  41. });
  42. for (int i=0; !t1AllSet.load(); ++i) {
  43. std::this_thread::sleep_for(10ms);
  44. }
  45. VERIFY(t1.joinable());
  46. VERIFY(t1ID == t1.get_id());
  47. stoken = t1.get_stop_token();
  48. VERIFY(!stoken.stop_requested());
  49. }
  50. VERIFY(stoken.stop_requested());
  51. }
  52. //------------------------------------------------------
  53. void test_stop_token()
  54. {
  55. // test the basic thread API (taking stop_token arg)
  56. std::stop_source ssource;
  57. std::stop_source origsource;
  58. VERIFY(ssource.stop_possible());
  59. VERIFY(!ssource.stop_requested());
  60. {
  61. std::jthread::id t1ID{std::this_thread::get_id()};
  62. std::atomic<bool> t1AllSet{false};
  63. std::atomic<bool> t1done{false};
  64. std::jthread t1([&t1ID, &t1AllSet, &t1done] (std::stop_token st) {
  65. // check some values of the started thread:
  66. t1ID = std::this_thread::get_id();
  67. t1AllSet.store(true);
  68. for (int i=0; !st.stop_requested(); ++i) {
  69. std::this_thread::sleep_for(100ms);
  70. }
  71. t1done.store(true);
  72. },
  73. ssource.get_token());
  74. for (int i=0; !t1AllSet.load(); ++i) {
  75. std::this_thread::sleep_for(10ms);
  76. }
  77. // and check all values:
  78. VERIFY(t1.joinable());
  79. VERIFY(t1ID == t1.get_id());
  80. std::this_thread::sleep_for(470ms);
  81. origsource = std::move(ssource);
  82. ssource = t1.get_stop_source();
  83. VERIFY(!ssource.stop_requested());
  84. auto ret = ssource.request_stop();
  85. VERIFY(ret);
  86. ret = ssource.request_stop();
  87. VERIFY(!ret);
  88. VERIFY(ssource.stop_requested());
  89. VERIFY(!t1done.load());
  90. VERIFY(!origsource.stop_requested());
  91. std::this_thread::sleep_for(470ms);
  92. origsource.request_stop();
  93. }
  94. VERIFY(origsource.stop_requested());
  95. VERIFY(ssource.stop_requested());
  96. }
  97. //------------------------------------------------------
  98. void test_join()
  99. {
  100. std::stop_source ssource;
  101. VERIFY(ssource.stop_possible());
  102. {
  103. std::jthread t1([](std::stop_token stoken) {
  104. for (int i=0; !stoken.stop_requested(); ++i) {
  105. std::this_thread::sleep_for(100ms);
  106. }
  107. });
  108. ssource = t1.get_stop_source();
  109. std::jthread t2([ssource] () mutable {
  110. for (int i=0; i < 10; ++i) {
  111. std::this_thread::sleep_for(70ms);
  112. }
  113. ssource.request_stop();
  114. });
  115. // wait for all thread to finish:
  116. t2.join();
  117. VERIFY(!t2.joinable());
  118. VERIFY(t1.joinable());
  119. t1.join();
  120. VERIFY(!t1.joinable());
  121. }
  122. }
  123. //------------------------------------------------------
  124. void test_detach()
  125. {
  126. std::stop_source ssource;
  127. VERIFY(ssource.stop_possible());
  128. std::atomic<bool> t1FinallyInterrupted{false};
  129. {
  130. std::jthread t0;
  131. std::jthread::id t1ID{std::this_thread::get_id()};
  132. bool t1IsInterrupted;
  133. std::stop_token t1InterruptToken;
  134. std::atomic<bool> t1AllSet{false};
  135. std::jthread t1([&t1ID, &t1IsInterrupted, &t1InterruptToken, &t1AllSet, &t1FinallyInterrupted]
  136. (std::stop_token stoken) {
  137. // check some values of the started thread:
  138. t1ID = std::this_thread::get_id();
  139. t1InterruptToken = stoken;
  140. t1IsInterrupted = stoken.stop_requested();
  141. VERIFY(stoken.stop_possible());
  142. VERIFY(!stoken.stop_requested());
  143. t1AllSet.store(true);
  144. for (int i=0; !stoken.stop_requested(); ++i) {
  145. std::this_thread::sleep_for(100ms);
  146. }
  147. t1FinallyInterrupted.store(true);
  148. });
  149. for (int i=0; !t1AllSet.load(); ++i) {
  150. std::this_thread::sleep_for(10ms);
  151. }
  152. VERIFY(!t0.joinable());
  153. VERIFY(t1.joinable());
  154. VERIFY(t1ID == t1.get_id());
  155. VERIFY(t1IsInterrupted == false);
  156. VERIFY(t1InterruptToken == t1.get_stop_source().get_token());
  157. ssource = t1.get_stop_source();
  158. VERIFY(t1InterruptToken.stop_possible());
  159. VERIFY(!t1InterruptToken.stop_requested());
  160. t1.detach();
  161. VERIFY(!t1.joinable());
  162. }
  163. VERIFY(!t1FinallyInterrupted.load());
  164. ssource.request_stop();
  165. VERIFY(ssource.stop_requested());
  166. for (int i=0; !t1FinallyInterrupted.load() && i < 100; ++i) {
  167. std::this_thread::sleep_for(100ms);
  168. }
  169. VERIFY(t1FinallyInterrupted.load());
  170. }
  171. //------------------------------------------------------
  172. void test_move_assignment()
  173. {
  174. std::jthread thread1([]{});
  175. std::jthread thread2([]{});
  176. const auto id2 = thread2.get_id();
  177. const auto ssource2 = thread2.get_stop_source();
  178. thread1 = std::move(thread2);
  179. VERIFY(thread1.get_id() == id2);
  180. VERIFY(thread2.get_id() == std::jthread::id());
  181. VERIFY(thread1.get_stop_source() == ssource2);
  182. VERIFY(!thread2.get_stop_source().stop_possible());
  183. }
  184. int main()
  185. {
  186. std::set_terminate([](){
  187. VERIFY(false);
  188. });
  189. test_no_stop_token();
  190. test_stop_token();
  191. test_join();
  192. test_detach();
  193. test_move_assignment();
  194. }