15# include <libloaderapi.h>
20# include <sys/prctl.h>
21# include <sys/resource.h>
22# include <sys/syscall.h>
40template <
typename ThreadType,
typename OwnershipTag>
58template <
typename ThreadType>
68 [[nodiscard]]
auto underlying() const noexcept -> ThreadType const&
93template <
typename ThreadType>
106 [[nodiscard]]
auto underlying() const noexcept -> ThreadType const&
167template <
typename ThreadType,
typename OwnershipTag = detail::OwningTag>
172 using id =
typename ThreadType::id;
193 underlying().detach();
197 [[nodiscard]]
auto joinable() const noexcept ->
bool
199 return underlying().joinable();
201 [[nodiscard]]
auto get_id() const noexcept ->
id
203 return underlying().get_id();
207 return underlying().native_handle();
215 [[nodiscard]]
auto get_name() const -> std::optional<std::
string>
247 DWORD priority_class;
248 if (nice_value <= -15)
250 priority_class = HIGH_PRIORITY_CLASS;
252 else if (nice_value <= -10)
254 priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
256 else if (nice_value < 10)
258 priority_class = NORMAL_PRIORITY_CLASS;
260 else if (nice_value < 19)
262 priority_class = BELOW_NORMAL_PRIORITY_CLASS;
266 priority_class = IDLE_PRIORITY_CLASS;
268 return SetPriorityClass(GetCurrentProcess(), priority_class) != 0;
270 return setpriority(PRIO_PROCESS, 0, nice_value) == 0;
278 DWORD priority_class = GetPriorityClass(GetCurrentProcess());
279 if (priority_class == 0)
285 switch (priority_class)
287 case HIGH_PRIORITY_CLASS:
289 case ABOVE_NORMAL_PRIORITY_CLASS:
291 case NORMAL_PRIORITY_CLASS:
293 case BELOW_NORMAL_PRIORITY_CLASS:
295 case IDLE_PRIORITY_CLASS:
302 int const nice = getpriority(PRIO_PROCESS, 0);
360 this->underlying() = std::move(t);
363 template <
typename F,
typename... Args>
366 this->underlying() = std::thread(std::forward<F>(f), std::forward<Args>(args)...);
374 this->underlying() = std::move(other.underlying());
383 this->underlying().join();
385 this->underlying() = std::move(other.underlying());
394 this->underlying().join();
401 return std::move(this->underlying());
404 explicit operator std::thread() &&
noexcept
406 return std::move(this->underlying());
410 template <
typename F,
typename... Args>
414 ThreadWrapper wrapper(std::forward<F>(f), std::forward<Args>(args)...);
448 auto get() noexcept -> std::thread&
450 return this->underlying();
452 [[nodiscard]]
auto get() const noexcept -> std::thread const&
454 return this->underlying();
495#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
496class JThreadWrapper :
public BaseThreadWrapper<std::jthread, detail::OwningTag>
504 this->underlying() = std::move(t);
508 auto release() noexcept -> std::jthread
510 return std::move(this->underlying());
513 explicit operator std::jthread() &&
noexcept
515 return std::move(this->underlying());
518 template <
typename F,
typename... Args>
521 this->underlying() = std::jthread(std::forward<F>(f), std::forward<Args>(args)...);
529 this->underlying() = std::move(other.underlying());
536 this->underlying() = std::move(other.underlying());
544 this->underlying().request_stop();
546 [[nodiscard]]
auto stop_requested() const noexcept ->
bool
548 return this->underlying().get_stop_token().stop_requested();
550 [[nodiscard]]
auto get_stop_token() const noexcept -> std::stop_token
552 return this->underlying().get_stop_token();
554 [[nodiscard]]
auto get_stop_source() noexcept -> std::stop_source
556 return this->underlying().get_stop_source();
560 template <
typename F,
typename... Args>
564 JThreadWrapper wrapper(std::forward<F>(f), std::forward<Args>(args)...);
565 (void)wrapper.set_name(name);
566 (void)wrapper.set_scheduling_policy(policy, priority);
604 this->underlying().request_stop();
606 [[nodiscard]]
auto stop_requested() const noexcept ->
bool
608 return this->underlying().get_stop_token().stop_requested();
610 [[nodiscard]]
auto get_stop_token() const noexcept -> std::stop_token
612 return this->underlying().get_stop_token();
614 [[nodiscard]]
auto get_stop_source() noexcept -> std::stop_source
616 return this->underlying().get_stop_source();
620 auto get() noexcept -> std::jthread&
622 return this->underlying();
624 [[nodiscard]]
auto get() const noexcept -> std::jthread const&
626 return this->underlying();
683 DIR* dir = opendir(
"/proc/self/task");
686 struct dirent* entry =
nullptr;
687 while ((entry = readdir(dir)) !=
nullptr)
689 if (entry->d_name[0] ==
'.')
691 std::string tid_str(entry->d_name);
692 std::string path = std::string(
"/proc/self/task/") + tid_str +
"/comm";
693 std::ifstream in(path);
697 std::getline(in, current);
698 if (!current.empty() && current.back() ==
'\n')
702 handle_ =
static_cast<pid_t
>(std::stoi(tid_str));
710 [[nodiscard]]
auto found() const noexcept ->
bool
722 return unexpected(std::make_error_code(std::errc::function_not_supported));
725 return unexpected(std::make_error_code(std::errc::no_such_process));
726 if (name.length() > 15)
727 return unexpected(std::make_error_code(std::errc::invalid_argument));
728 std::string path = std::string(
"/proc/self/task/") + std::to_string(handle_) +
"/comm";
729 std::ofstream out(path);
731 return unexpected(std::error_code(errno, std::generic_category()));
735 return unexpected(std::error_code(errno, std::generic_category()));
740 [[nodiscard]]
auto get_name() const -> std::optional<std::
string>
747 std::string path = std::string(
"/proc/self/task/") + std::to_string(handle_) +
"/comm";
748 std::ifstream in(path);
752 std::getline(in, current);
753 if (!current.empty() && current.back() ==
'\n')
767 return unexpected(std::make_error_code(std::errc::function_not_supported));
770 return unexpected(std::make_error_code(std::errc::no_such_process));
779 return unexpected(std::make_error_code(std::errc::function_not_supported));
782 return unexpected(std::make_error_code(std::errc::no_such_process));
790 return unexpected(std::make_error_code(std::errc::function_not_supported));
793 return unexpected(std::make_error_code(std::errc::no_such_process));
827 return std::thread::hardware_concurrency();
833 return GetCurrentThreadId();
835 return static_cast<pid_t
>(syscall(SYS_gettid));
846 const int policy = sched_getscheduler(0);
858 HANDLE thread = GetCurrentThread();
859 int priority = GetThreadPriority(thread);
860 if (priority == THREAD_PRIORITY_ERROR_RETURN)
867 if (sched_getparam(0, ¶m) == 0)
869 return param.sched_priority;
Polymorphic base providing common thread management operations.
auto native_handle() noexcept -> native_handle_type
static auto get_nice_value() -> std::optional< int >
static auto set_nice_value(int nice_value) -> bool
typename ThreadType::native_handle_type native_handle_type
typename ThreadType::id id
auto get_affinity() const -> std::optional< ThreadAffinity >
auto get_name() const -> std::optional< std::string >
auto set_scheduling_policy(SchedulingPolicy policy, ThreadPriority priority) -> expected< void, std::error_code >
auto get_id() const noexcept -> id
auto set_name(std::string const &name) -> expected< void, std::error_code >
auto set_priority(ThreadPriority priority) -> expected< void, std::error_code >
BaseThreadWrapper(ThreadType &t)
BaseThreadWrapper()=default
virtual ~BaseThreadWrapper()=default
auto joinable() const noexcept -> bool
auto set_affinity(ThreadAffinity const &affinity) -> expected< void, std::error_code >
Manages a set of CPU indices to which a thread may be bound.
auto set_name(std::string const &name) const -> expected< void, std::error_code >
auto set_affinity(ThreadAffinity const &affinity) const -> expected< void, std::error_code >
auto native_handle() const noexcept -> native_handle_type
auto set_priority(ThreadPriority priority) const -> expected< void, std::error_code >
auto set_scheduling_policy(SchedulingPolicy policy, ThreadPriority priority) const -> expected< void, std::error_code >
auto get_name() const -> std::optional< std::string >
ThreadByNameView(const std::string &name)
auto found() const noexcept -> bool
Static utility class providing hardware and scheduling introspection.
static auto get_current_priority() -> std::optional< int >
static auto get_thread_id()
static auto get_current_policy() -> std::optional< SchedulingPolicy >
static auto hardware_concurrency() -> unsigned int
Value-semantic wrapper for a thread scheduling priority.
Non-owning view over an externally managed std::thread.
ThreadWrapperView(std::thread &t)
auto get() const noexcept -> std::thread const &
auto get() noexcept -> std::thread &
Owning wrapper around std::thread with RAII join-on-destroy semantics.
auto operator=(ThreadWrapper const &) -> ThreadWrapper &=delete
auto release() noexcept -> std::thread
auto operator=(ThreadWrapper &&other) noexcept -> ThreadWrapper &
operator std::thread() &&noexcept
~ThreadWrapper() override
static auto create_with_config(std::string const &name, SchedulingPolicy policy, ThreadPriority priority, F &&f, Args &&... args) -> ThreadWrapper
ThreadWrapper(std::thread &&t) noexcept
ThreadWrapper(ThreadWrapper const &)=delete
ThreadWrapper(ThreadWrapper &&other) noexcept
ThreadWrapper(F &&f, Args &&... args)
auto underlying() const noexcept -> ThreadType const &
ThreadType * external_thread_
ThreadStorage(ThreadType &t)
auto underlying() noexcept -> ThreadType &
auto underlying() noexcept -> ThreadType &
auto underlying() const noexcept -> ThreadType const &
A result type that holds either a value of type T or an error of type E.
Exception thrown by expected::value() when the object is in the error state.
Polyfill for std::expected (C++23) for pre-C++23 compilers.
auto apply_affinity(pthread_t handle, ThreadAffinity const &affinity) -> expected< void, std::error_code >
auto apply_priority(pthread_t handle, ThreadPriority priority) -> expected< void, std::error_code >
auto read_name(pthread_t handle) -> std::optional< std::string >
auto apply_scheduling_policy(pthread_t handle, SchedulingPolicy policy, ThreadPriority priority) -> expected< void, std::error_code >
auto apply_name(pthread_t handle, std::string const &name) -> expected< void, std::error_code >
auto read_affinity(pthread_t handle) -> std::optional< ThreadAffinity >
SchedulingPolicy
Enumeration of available thread scheduling policies.
@ OTHER
Standard round-robin time-sharing.
ThreadWrapperView JThreadWrapperView
ThreadWrapper JThreadWrapper
Owning wrapper around std::jthread with cooperative cancellation (C++20).
Scheduling policies, thread priority, and CPU affinity types.
Tag type selecting non-owning (pointer) storage in ThreadStorage.
Tag type selecting owning (value) storage in ThreadStorage.