Files
clang-p2996/libcxx/include/__thread/jthread.h
Louis Dionne 7162fd750e [libc++] Split the monolithic __threading_support header (#79654)
The <__threading_support> header is a huge beast and it's really
difficult to navigate. I find myself struggling to find what I want
every time I have to open it, and I've been considering splitting it up
for years for that reason.

This patch aims not to contain any functional change. The various
implementations of the threading base are simply moved to separate
headers and then the individual headers are simplified in mechanical
ways. For example, we used to have redundant declarations of all the
functions at the top of `__threading_support`, and those are removed
since they are not needed anymore. The various #ifdefs are also
simplified and removed when they become unnecessary.

Finally, this patch adds documentation for the API we expect from any
threading implementation.
2024-01-30 08:35:15 -05:00

136 lines
4.5 KiB
C++

// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___THREAD_JTHREAD_H
#define _LIBCPP___THREAD_JTHREAD_H
#include <__availability>
#include <__config>
#include <__functional/invoke.h>
#include <__stop_token/stop_source.h>
#include <__stop_token/stop_token.h>
#include <__thread/support.h>
#include <__thread/thread.h>
#include <__type_traits/decay.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/remove_cvref.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
_LIBCPP_BEGIN_NAMESPACE_STD
class _LIBCPP_AVAILABILITY_SYNC jthread {
public:
// types
using id = thread::id;
using native_handle_type = thread::native_handle_type;
// [thread.jthread.cons], constructors, move, and assignment
_LIBCPP_HIDE_FROM_ABI jthread() noexcept : __stop_source_(std::nostopstate) {}
template <class _Fun, class... _Args>
_LIBCPP_HIDE_FROM_ABI explicit jthread(_Fun&& __fun, _Args&&... __args)
requires(!std::is_same_v<remove_cvref_t<_Fun>, jthread>)
: __stop_source_(),
__thread_(__init_thread(__stop_source_, std::forward<_Fun>(__fun), std::forward<_Args>(__args)...)) {
static_assert(is_constructible_v<decay_t<_Fun>, _Fun>);
static_assert((is_constructible_v<decay_t<_Args>, _Args> && ...));
static_assert(is_invocable_v<decay_t<_Fun>, decay_t<_Args>...> ||
is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>);
}
_LIBCPP_HIDE_FROM_ABI ~jthread() {
if (joinable()) {
request_stop();
join();
}
}
jthread(const jthread&) = delete;
_LIBCPP_HIDE_FROM_ABI jthread(jthread&&) noexcept = default;
jthread& operator=(const jthread&) = delete;
_LIBCPP_HIDE_FROM_ABI jthread& operator=(jthread&& __other) noexcept {
if (this != &__other) {
if (joinable()) {
request_stop();
join();
}
__stop_source_ = std::move(__other.__stop_source_);
__thread_ = std::move(__other.__thread_);
}
return *this;
}
// [thread.jthread.mem], members
_LIBCPP_HIDE_FROM_ABI void swap(jthread& __other) noexcept {
std::swap(__stop_source_, __other.__stop_source_);
std::swap(__thread_, __other.__thread_);
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool joinable() const noexcept { return get_id() != id(); }
_LIBCPP_HIDE_FROM_ABI void join() { __thread_.join(); }
_LIBCPP_HIDE_FROM_ABI void detach() { __thread_.detach(); }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI id get_id() const noexcept { return __thread_.get_id(); }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __thread_.native_handle(); }
// [thread.jthread.stop], stop token handling
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_source get_stop_source() noexcept { return __stop_source_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI stop_token get_stop_token() const noexcept { return __stop_source_.get_token(); }
_LIBCPP_HIDE_FROM_ABI bool request_stop() noexcept { return __stop_source_.request_stop(); }
// [thread.jthread.special], specialized algorithms
_LIBCPP_HIDE_FROM_ABI friend void swap(jthread& __lhs, jthread& __rhs) noexcept { __lhs.swap(__rhs); }
// [thread.jthread.static], static members
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static unsigned int hardware_concurrency() noexcept {
return thread::hardware_concurrency();
}
private:
template <class _Fun, class... _Args>
_LIBCPP_HIDE_FROM_ABI static thread __init_thread(const stop_source& __ss, _Fun&& __fun, _Args&&... __args) {
if constexpr (is_invocable_v<decay_t<_Fun>, stop_token, decay_t<_Args>...>) {
return thread(std::forward<_Fun>(__fun), __ss.get_token(), std::forward<_Args>(__args)...);
} else {
return thread(std::forward<_Fun>(__fun), std::forward<_Args>(__args)...);
}
}
stop_source __stop_source_;
thread __thread_;
};
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN)
_LIBCPP_POP_MACROS
#endif // _LIBCPP___THREAD_JTHREAD_H