51 using native_handle_type = pthread_t;
54 PThreadWrapper() : thread_(0), joined_(
false)
58 template <
typename F,
typename... Args>
59 explicit PThreadWrapper(F&& func, Args&&... args) : thread_(0), joined_(
false)
64 std::make_unique<std::function<void()>>(std::bind(std::forward<F>(func), std::forward<Args>(args)...));
66 int const result = pthread_create(&thread_,
nullptr, thread_function, callable.release());
70 throw std::runtime_error(
"Failed to create pthread: " + std::to_string(result));
75 PThreadWrapper(PThreadWrapper
const&) =
delete;
76 auto operator=(PThreadWrapper
const&) -> PThreadWrapper& =
delete;
79 PThreadWrapper(PThreadWrapper&& other) noexcept : thread_(other.thread_), joined_(other.joined_.load())
82 other.joined_.store(
true);
85 auto operator=(PThreadWrapper&& other)
noexcept -> PThreadWrapper&
93 thread_ = other.thread_;
94 joined_.store(other.joined_.load());
96 other.joined_.store(
true);
115 int const result = pthread_join(thread_, &retval);
127 int const result = pthread_detach(thread_);
135 [[nodiscard]]
auto joinable()
const ->
bool
137 return thread_ != 0 && !joined_;
140 [[nodiscard]]
auto get_id()
const ->
id
144 [[nodiscard]]
auto native_handle()
const -> native_handle_type
152 if (name.length() > 15)
154 if (pthread_setname_np(thread_, name.c_str()) == 0)
159 [[nodiscard]]
auto get_name()
const -> std::optional<std::string>
162 if (pthread_getname_np(thread_, name,
sizeof(name)) == 0)
164 return std::string(name);
171 int const policy = SCHED_OTHER;
172 auto params_result = SchedulerParams::create_for_policy(SchedulingPolicy::OTHER, priority);
174 if (!params_result.has_value())
179 if (pthread_setschedparam(thread_, policy, ¶ms_result.value()) == 0)
181 return unexpected(std::error_code(errno, std::generic_category()));
184 [[nodiscard]]
auto set_scheduling_policy(SchedulingPolicy policy,
ThreadPriority priority)
const
187 int const policy_int =
static_cast<int>(policy);
188 auto params_result = SchedulerParams::create_for_policy(policy, priority);
190 if (!params_result.has_value())
195 if (pthread_setschedparam(thread_, policy_int, ¶ms_result.value()) == 0)
197 return unexpected(std::error_code(errno, std::generic_category()));
202 if (pthread_setaffinity_np(thread_,
sizeof(cpu_set_t), &affinity.native_handle()) == 0)
204 return unexpected(std::error_code(errno, std::generic_category()));
207 [[nodiscard]]
auto get_affinity()
const -> std::optional<ThreadAffinity>
210 if (pthread_getaffinity_np(thread_,
sizeof(cpu_set_t),
const_cast<cpu_set_t*
>(&affinity.native_handle())) == 0)
220 if (pthread_cancel(thread_) == 0)
222 return unexpected(std::error_code(errno, std::generic_category()));
227 int const state = enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE;
229 if (pthread_setcancelstate(state, &old_state) == 0)
231 return unexpected(std::error_code(errno, std::generic_category()));
236 int const type = asynchronous ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED;
238 if (pthread_setcanceltype(type, &old_type) == 0)
240 return unexpected(std::error_code(errno, std::generic_category()));
244 template <
typename F,
typename... Args>
245 static auto create_with_config(std::string
const& name, SchedulingPolicy policy,
ThreadPriority priority, F&& f,
246 Args&&... args) -> PThreadWrapper
249 PThreadWrapper wrapper(std::forward<F>(f), std::forward<Args>(args)...);
250 (void)wrapper.set_name(name);
251 (void)wrapper.set_scheduling_policy(policy, priority);
255 template <
typename F,
typename... Args>
256 static auto create_with_attributes(pthread_attr_t
const& attr, F&& func, Args&&... args) -> PThreadWrapper
259 PThreadWrapper wrapper;
261 std::make_unique<std::function<void()>>(std::bind(std::forward<F>(func), std::forward<Args>(args)...));
263 int const result = pthread_create(&wrapper.thread_, &attr, thread_function, callable.release());
267 throw std::runtime_error(
"Failed to create pthread with attributes: " + std::to_string(result));
275 std::atomic<bool> joined_;
277 static auto thread_function(
void* arg) ->
void*
279 std::unique_ptr<std::function<void()>> func(
static_cast<std::function<
void()
>*>(arg));
306class PThreadAttributes
311 if (pthread_attr_init(&attr_) != 0)
313 throw std::runtime_error(
"Failed to initialize pthread attributes");
319 pthread_attr_destroy(&attr_);
323 PThreadAttributes(PThreadAttributes
const&) =
delete;
324 auto operator=(PThreadAttributes
const&) -> PThreadAttributes& =
delete;
327 PThreadAttributes(PThreadAttributes&& other) noexcept : attr_(other.attr_)
329 if (pthread_attr_init(&other.attr_) != 0)
335 auto operator=(PThreadAttributes&& other)
noexcept -> PThreadAttributes&
339 pthread_attr_destroy(&attr_);
341 if (pthread_attr_init(&other.attr_) != 0)
349 [[nodiscard]]
auto get()
const -> pthread_attr_t
const&
353 auto get() -> pthread_attr_t&
359 auto set_detach_state(
bool detached) ->
bool
361 int const state = detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;
362 return pthread_attr_setdetachstate(&attr_, state) == 0;
365 auto set_stack_size(
size_t stack_size) ->
bool
367 return pthread_attr_setstacksize(&attr_, stack_size) == 0;
370 auto set_guard_size(
size_t guard_size) ->
bool
372 return pthread_attr_setguardsize(&attr_, guard_size) == 0;
375 auto set_scheduling_policy(SchedulingPolicy policy) ->
bool
377 int const policy_int =
static_cast<int>(policy);
378 return pthread_attr_setschedpolicy(&attr_, policy_int) == 0;
384 param.sched_priority = priority.value();
385 return pthread_attr_setschedparam(&attr_, ¶m) == 0;
388 auto set_inherit_sched(
bool inherit) ->
bool
390 int const inherit_val = inherit ? PTHREAD_INHERIT_SCHED : PTHREAD_EXPLICIT_SCHED;
391 return pthread_attr_setinheritsched(&attr_, inherit_val) == 0;
394 auto set_scope(
bool system_scope) ->
bool
396 int const scope = system_scope ? PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS;
397 return pthread_attr_setscope(&attr_, scope) == 0;
401 [[nodiscard]]
auto get_detach_state()
const -> std::optional<bool>
404 if (pthread_attr_getdetachstate(&attr_, &state) == 0)
406 return state == PTHREAD_CREATE_DETACHED;
411 [[nodiscard]]
auto get_stack_size()
const -> std::optional<size_t>
414 if (pthread_attr_getstacksize(&attr_, &stack_size) == 0)
421 [[nodiscard]]
auto get_guard_size()
const -> std::optional<size_t>
424 if (pthread_attr_getguardsize(&attr_, &guard_size) == 0)
432 pthread_attr_t attr_;