30 using native_handle_type = pthread_t;
33 PThreadWrapper() : thread_(0), joined_(
false)
37 template <
typename F,
typename... Args>
38 explicit PThreadWrapper(F&& func, Args&&... args) : thread_(0), joined_(
false)
43 std::make_unique<std::function<void()>>(std::bind(std::forward<F>(func), std::forward<Args>(args)...));
45 int const result = pthread_create(&thread_,
nullptr, thread_function, callable.release());
49 throw std::runtime_error(
"Failed to create pthread: " + std::to_string(result));
54 PThreadWrapper(PThreadWrapper
const&) =
delete;
55 auto operator=(PThreadWrapper
const&) -> PThreadWrapper& =
delete;
58 PThreadWrapper(PThreadWrapper&& other) noexcept : thread_(other.thread_), joined_(other.joined_.load())
61 other.joined_.store(
true);
64 auto operator=(PThreadWrapper&& other)
noexcept -> PThreadWrapper&
72 thread_ = other.thread_;
73 joined_.store(other.joined_.load());
75 other.joined_.store(
true);
94 int const result = pthread_join(thread_, &retval);
106 int const result = pthread_detach(thread_);
114 [[nodiscard]]
auto joinable()
const ->
bool
116 return thread_ != 0 && !joined_;
119 [[nodiscard]]
auto get_id()
const ->
id
123 [[nodiscard]]
auto native_handle()
const -> native_handle_type
131 if (name.length() > 15)
133 if (pthread_setname_np(thread_, name.c_str()) == 0)
138 [[nodiscard]]
auto get_name()
const -> std::optional<std::string>
141 if (pthread_getname_np(thread_, name,
sizeof(name)) == 0)
143 return std::string(name);
150 int const policy = SCHED_OTHER;
151 auto params_result = SchedulerParams::create_for_policy(SchedulingPolicy::OTHER, priority);
153 if (!params_result.has_value())
158 if (pthread_setschedparam(thread_, policy, ¶ms_result.value()) == 0)
160 return unexpected(std::error_code(errno, std::generic_category()));
163 [[nodiscard]]
auto set_scheduling_policy(SchedulingPolicy policy,
ThreadPriority priority)
const
166 int const policy_int =
static_cast<int>(policy);
167 auto params_result = SchedulerParams::create_for_policy(policy, priority);
169 if (!params_result.has_value())
174 if (pthread_setschedparam(thread_, policy_int, ¶ms_result.value()) == 0)
176 return unexpected(std::error_code(errno, std::generic_category()));
181 if (pthread_setaffinity_np(thread_,
sizeof(cpu_set_t), &affinity.native_handle()) == 0)
183 return unexpected(std::error_code(errno, std::generic_category()));
186 [[nodiscard]]
auto get_affinity()
const -> std::optional<ThreadAffinity>
189 if (pthread_getaffinity_np(thread_,
sizeof(cpu_set_t),
const_cast<cpu_set_t*
>(&affinity.native_handle())) == 0)
199 if (pthread_cancel(thread_) == 0)
201 return unexpected(std::error_code(errno, std::generic_category()));
206 int const state = enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE;
208 if (pthread_setcancelstate(state, &old_state) == 0)
210 return unexpected(std::error_code(errno, std::generic_category()));
215 int const type = asynchronous ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED;
217 if (pthread_setcanceltype(type, &old_type) == 0)
219 return unexpected(std::error_code(errno, std::generic_category()));
223 template <
typename F,
typename... Args>
224 static auto create_with_config(std::string
const& name, SchedulingPolicy policy,
ThreadPriority priority, F&& f,
225 Args&&... args) -> PThreadWrapper
228 PThreadWrapper wrapper(std::forward<F>(f), std::forward<Args>(args)...);
229 (void)wrapper.set_name(name);
230 (void)wrapper.set_scheduling_policy(policy, priority);
234 template <
typename F,
typename... Args>
235 static auto create_with_attributes(pthread_attr_t
const& attr, F&& func, Args&&... args) -> PThreadWrapper
238 PThreadWrapper wrapper;
240 std::make_unique<std::function<void()>>(std::bind(std::forward<F>(func), std::forward<Args>(args)...));
242 int const result = pthread_create(&wrapper.thread_, &attr, thread_function, callable.release());
246 throw std::runtime_error(
"Failed to create pthread with attributes: " + std::to_string(result));
254 std::atomic<bool> joined_;
256 static auto thread_function(
void* arg) ->
void*
258 std::unique_ptr<std::function<void()>> func(
static_cast<std::function<
void()
>*>(arg));
276class PThreadAttributes
281 if (pthread_attr_init(&attr_) != 0)
283 throw std::runtime_error(
"Failed to initialize pthread attributes");
289 pthread_attr_destroy(&attr_);
293 PThreadAttributes(PThreadAttributes
const&) =
delete;
294 auto operator=(PThreadAttributes
const&) -> PThreadAttributes& =
delete;
297 PThreadAttributes(PThreadAttributes&& other) noexcept : attr_(other.attr_)
299 if (pthread_attr_init(&other.attr_) != 0)
305 auto operator=(PThreadAttributes&& other)
noexcept -> PThreadAttributes&
309 pthread_attr_destroy(&attr_);
311 if (pthread_attr_init(&other.attr_) != 0)
319 [[nodiscard]]
auto get()
const -> pthread_attr_t
const&
323 auto get() -> pthread_attr_t&
329 auto set_detach_state(
bool detached) ->
bool
331 int const state = detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;
332 return pthread_attr_setdetachstate(&attr_, state) == 0;
335 auto set_stack_size(
size_t stack_size) ->
bool
337 return pthread_attr_setstacksize(&attr_, stack_size) == 0;
340 auto set_guard_size(
size_t guard_size) ->
bool
342 return pthread_attr_setguardsize(&attr_, guard_size) == 0;
345 auto set_scheduling_policy(SchedulingPolicy policy) ->
bool
347 int const policy_int =
static_cast<int>(policy);
348 return pthread_attr_setschedpolicy(&attr_, policy_int) == 0;
354 param.sched_priority = priority.value();
355 return pthread_attr_setschedparam(&attr_, ¶m) == 0;
358 auto set_inherit_sched(
bool inherit) ->
bool
360 int const inherit_val = inherit ? PTHREAD_INHERIT_SCHED : PTHREAD_EXPLICIT_SCHED;
361 return pthread_attr_setinheritsched(&attr_, inherit_val) == 0;
364 auto set_scope(
bool system_scope) ->
bool
366 int const scope = system_scope ? PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
367 return pthread_attr_setscope(&attr_, scope) == 0;
371 [[nodiscard]]
auto get_detach_state()
const -> std::optional<bool>
374 if (pthread_attr_getdetachstate(&attr_, &state) == 0)
376 return state == PTHREAD_CREATE_DETACHED;
381 [[nodiscard]]
auto get_stack_size()
const -> std::optional<size_t>
384 if (pthread_attr_getstacksize(&attr_, &stack_size) == 0)
391 [[nodiscard]]
auto get_guard_size()
const -> std::optional<size_t>
394 if (pthread_attr_getguardsize(&attr_, &guard_size) == 0)
402 pthread_attr_t attr_;