brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · e8a57cc Raw
160 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// UNSUPPORTED: no-threads10// UNSUPPORTED: c++03, c++11, c++14, c++1711 12// template<class F, class... Args>13// explicit jthread(F&& f, Args&&... args);14 15#include <cassert>16#include <stop_token>17#include <thread>18#include <type_traits>19#include <utility>20 21#include "test_macros.h"22 23template <class... Args>24struct Func {25  void operator()(Args...) const;26};27 28// Constraints: remove_cvref_t<F> is not the same type as jthread.29static_assert(std::is_constructible_v<std::jthread, Func<>>);30static_assert(std::is_constructible_v<std::jthread, Func<int>, int>);31static_assert(!std::is_constructible_v<std::jthread, std::jthread const&>);32 33// explicit34template <class T>35void conversion_test(T);36 37template <class T, class... Args>38concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };39 40static_assert(!ImplicitlyConstructible<std::jthread, Func<>>);41static_assert(!ImplicitlyConstructible<std::jthread, Func<int>, int>);42 43int main(int, char**) {44  // Effects: Initializes ssource45  // Postconditions: get_id() != id() is true and ssource.stop_possible() is true46  // and *this represents the newly started thread.47  {48    std::jthread jt{[] {}};49    assert(jt.get_stop_source().stop_possible());50    assert(jt.get_id() != std::jthread::id());51  }52 53  // The new thread of execution executes54  // invoke(auto(std::forward<F>(f)), get_stop_token(), auto(std::forward<Args>(args))...)55  // if that expression is well-formed,56  {57    int result = 0;58    std::jthread jt{[&result](std::stop_token st, int i) {59                      assert(st.stop_possible());60                      assert(!st.stop_requested());61                      result += i;62                    },63                    5};64    jt.join();65    assert(result == 5);66  }67 68  // otherwise69  // invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)70  {71    int result = 0;72    std::jthread jt{[&result](int i) { result += i; }, 5};73    jt.join();74    assert(result == 5);75  }76 77  // with the values produced by auto being materialized ([conv.rval]) in the constructing thread.78  {79    struct TrackThread {80      std::jthread::id threadId;81      bool copyConstructed = false;82      bool moveConstructed = false;83 84      TrackThread() : threadId(std::this_thread::get_id()) {}85      TrackThread(const TrackThread&) : threadId(std::this_thread::get_id()), copyConstructed(true) {}86      TrackThread(TrackThread&&) : threadId(std::this_thread::get_id()), moveConstructed(true) {}87    };88 89    auto mainThread = std::this_thread::get_id();90 91    TrackThread arg1;92    std::jthread jt1{[mainThread](const TrackThread& arg) {93                       assert(arg.threadId == mainThread);94                       assert(arg.threadId != std::this_thread::get_id());95                       assert(arg.copyConstructed);96                     },97                     arg1};98 99    TrackThread arg2;100    std::jthread jt2{[mainThread](const TrackThread& arg) {101                       assert(arg.threadId == mainThread);102                       assert(arg.threadId != std::this_thread::get_id());103                       assert(arg.moveConstructed);104                     },105                     std::move(arg2)};106  }107 108#if !defined(TEST_HAS_NO_EXCEPTIONS)109  // [Note 1: This implies that any exceptions not thrown from the invocation of the copy110  // of f will be thrown in the constructing thread, not the new thread. - end note]111  {112    struct Exception {113      std::jthread::id threadId;114    };115    struct ThrowOnCopyFunc {116      ThrowOnCopyFunc() = default;117      ThrowOnCopyFunc(const ThrowOnCopyFunc&) { throw Exception{std::this_thread::get_id()}; }118      void operator()() const {}119    };120    ThrowOnCopyFunc f1;121    try {122      std::jthread jt{f1};123      assert(false);124    } catch (const Exception& e) {125      assert(e.threadId == std::this_thread::get_id());126    }127  }128#endif // !defined(TEST_HAS_NO_EXCEPTIONS)129 130  // Synchronization: The completion of the invocation of the constructor131  // synchronizes with the beginning of the invocation of the copy of f.132  {133    int flag = 0;134    struct Arg {135      int& flag_;136      Arg(int& f) : flag_(f) {}137 138      Arg(const Arg& other) : flag_(other.flag_) { flag_ = 5; }139    };140 141    Arg arg(flag);142    std::jthread jt(143        [&flag](const auto&) {144          assert(flag == 5); // happens-after the copy-construction of arg145        },146        arg);147  }148 149  // Per https://eel.is/c++draft/thread.jthread.class#thread.jthread.cons-8:150  //151  // Throws: system_error if unable to start the new thread.152  // Error conditions:153  // resource_unavailable_try_again - the system lacked the necessary resources to create another thread,154  // or the system-imposed limit on the number of threads in a process would be exceeded.155  //156  // Unfortunately, this is extremely hard to test portably so we don't have a test for this error condition right now.157 158  return 0;159}160