1 //===----------------------------------------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // UNSUPPORTED: no-threads 10 // UNSUPPORTED: c++03, c++11, c++14, c++17 11 // XFAIL: availability-synchronization_library-missing 12 // ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-self-move 13 14 // jthread& operator=(jthread&&) noexcept; 15 16 #include <atomic> 17 #include <cassert> 18 #include <concepts> 19 #include <stop_token> 20 #include <thread> 21 #include <type_traits> 22 #include <utility> 23 #include <vector> 24 25 #include "make_test_thread.h" 26 #include "test_macros.h" 27 28 static_assert(std::is_nothrow_move_assignable_v<std::jthread>); 29 30 int main(int, char**) { 31 // If &x == this is true, there are no effects. 32 { 33 std::jthread j = support::make_test_jthread([] {}); 34 auto id = j.get_id(); 35 auto ssource = j.get_stop_source(); 36 j = std::move(j); 37 assert(j.get_id() == id); 38 assert(j.get_stop_source() == ssource); 39 } 40 41 // if joinable() is true, calls request_stop() and then join() 42 // request_stop is called 43 { 44 std::jthread j1 = support::make_test_jthread([] {}); 45 bool called = false; 46 std::stop_callback cb(j1.get_stop_token(), [&called] { called = true; }); 47 48 std::jthread j2 = support::make_test_jthread([] {}); 49 j1 = std::move(j2); 50 assert(called); 51 } 52 53 // if joinable() is true, calls request_stop() and then join() 54 // join is called 55 { 56 std::atomic_int calledTimes = 0; 57 std::vector<std::jthread> jts; 58 constexpr auto numberOfThreads = 10u; 59 jts.reserve(numberOfThreads); 60 for (auto i = 0u; i < numberOfThreads; ++i) { 61 jts.emplace_back(support::make_test_jthread([&] { 62 std::this_thread::sleep_for(std::chrono::milliseconds(2)); 63 calledTimes.fetch_add(1, std::memory_order_relaxed); 64 })); 65 } 66 67 for (auto i = 0u; i < numberOfThreads; ++i) { 68 jts[i] = std::jthread{}; 69 } 70 71 // If join was called as expected, calledTimes must equal to numberOfThreads 72 // If join was not called, there is a chance that the check below happened 73 // before test threads incrementing the counter, thus calledTimed would 74 // be less than numberOfThreads. 75 // This is not going to catch issues 100%. Creating more threads to increase 76 // the probability of catching the issue 77 assert(calledTimes.load(std::memory_order_relaxed) == numberOfThreads); 78 } 79 80 // then assigns the state of x to *this 81 { 82 std::jthread j1 = support::make_test_jthread([] {}); 83 std::jthread j2 = support::make_test_jthread([] {}); 84 auto id2 = j2.get_id(); 85 auto ssource2 = j2.get_stop_source(); 86 87 j1 = std::move(j2); 88 89 assert(j1.get_id() == id2); 90 assert(j1.get_stop_source() == ssource2); 91 } 92 93 // sets x to a default constructed state 94 { 95 std::jthread j1 = support::make_test_jthread([] {}); 96 std::jthread j2 = support::make_test_jthread([] {}); 97 j1 = std::move(j2); 98 99 assert(j2.get_id() == std::jthread::id()); 100 assert(!j2.get_stop_source().stop_possible()); 101 } 102 103 // joinable is false 104 { 105 std::jthread j1; 106 std::jthread j2 = support::make_test_jthread([] {}); 107 108 auto j2Id = j2.get_id(); 109 110 j1 = std::move(j2); 111 112 assert(j1.get_id() == j2Id); 113 } 114 115 return 0; 116 } 117