Loading...
Searching...
No Matches
thread.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Hamburg University of Applied Sciences (HAW)
3 *
4 * This file is subject to the terms and conditions of the GNU Lesser
5 * General Public License v2.1. See the file LICENSE in the top level
6 * directory for more details.
7 */
8
24#ifndef RIOT_THREAD_HPP
25#define RIOT_THREAD_HPP
26
27#include "time.h"
28#include "thread.h"
29
30#include <array>
31#include <tuple>
32#include <atomic>
33#include <memory>
34#include <utility>
35#include <exception>
36#include <stdexcept>
37#include <functional>
38#include <type_traits>
39
40#include "riot/mutex.hpp"
41#include "riot/chrono.hpp"
43
45
46namespace riot {
47
52 thread_data() : ref_count{2}, joining_thread{KERNEL_PID_UNDEF} {
53 // nop
54 }
56 std::atomic<unsigned> ref_count;
57 kernel_pid_t joining_thread;
58 std::array<char, THREAD_STACKSIZE_MAIN> stack;
60};
61
72 if (--ptr->ref_count == 0) {
73 delete ptr;
74 }
75 }
76};
77
84class thread_id {
85 template <class T, class Traits>
86 friend std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
87 <T, Traits>& out,
88 thread_id id);
89 friend class thread;
90
91public:
95 inline thread_id() noexcept : m_handle{KERNEL_PID_UNDEF} {}
99 explicit inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
100
104 inline bool operator==(thread_id other) noexcept {
105 return m_handle == other.m_handle;
106 }
110 inline bool operator!=(thread_id other) noexcept {
111 return !(m_handle == other.m_handle);
112 }
116 inline bool operator<(thread_id other) noexcept {
117 return m_handle < other.m_handle;
118 }
122 inline bool operator<=(thread_id other) noexcept {
123 return !(m_handle > other.m_handle);
124 }
128 inline bool operator>(thread_id other) noexcept {
129 return m_handle > other.m_handle;
130 }
134 inline bool operator>=(thread_id other) noexcept {
135 return !(m_handle < other.m_handle);
136 }
137
138private:
139 kernel_pid_t m_handle;
140};
141
145template <class T, class Traits>
146inline std::basic_ostream<T, Traits>& operator<<(std::basic_ostream
147 <T, Traits>& out,
148 thread_id id) {
149 return out << id.m_handle;
150}
151
152namespace this_thread {
153
157inline thread_id get_id() noexcept { return thread_id{thread_getpid()}; }
161inline void yield() noexcept { thread_yield(); }
166void sleep_for(const std::chrono::microseconds& us);
171template <class Rep, class Period>
172void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
173 using namespace std::chrono;
174 if (sleep_duration > sleep_duration.zero()) {
175 constexpr duration<long double> max = microseconds::max();
176 microseconds us;
177 if (sleep_duration < max) {
178 us = duration_cast<microseconds>(sleep_duration);
179 if (us.count() == 0) {
180 // wait at least 1
181 us = microseconds(1);
182 }
183 if (us < sleep_duration) {
184 ++us;
185 }
186 } else {
187 us = microseconds::max();
188 }
189 sleep_for(us);
190 }
191}
197inline void sleep_until(const riot::time_point& sleep_time) {
198 mutex mtx;
199 condition_variable cv;
200 unique_lock<mutex> lk(mtx);
201 while (riot::now() < sleep_time) {
202 cv.wait_until(lk, sleep_time);
203 }
204}
205} // namespace this_thread
206
214class thread {
215public:
219 using id = thread_id;
224
228 inline thread() noexcept : m_handle{KERNEL_PID_UNDEF} {}
234 template <class F, class... Args>
235 explicit thread(F&& f, Args&&... args);
236
240 thread(const thread&) = delete;
241
245 inline thread(thread&& t) noexcept : m_handle{t.m_handle} {
246 t.m_handle = KERNEL_PID_UNDEF;
247 std::swap(m_data, t.m_data);
248 }
249
250 ~thread();
251
255 thread& operator=(const thread&) = delete;
256
260 thread& operator=(thread&&) noexcept;
261
266 void swap(thread& t) noexcept {
267 std::swap(m_data, t.m_data);
268 std::swap(m_handle, t.m_handle);
269 }
270
275 inline bool joinable() const noexcept {
276 return m_handle != KERNEL_PID_UNDEF;
277 }
282 void join();
288 void detach();
292 inline id get_id() const noexcept { return thread_id{m_handle}; }
296 inline native_handle_type native_handle() noexcept { return m_handle; }
297
303 static unsigned hardware_concurrency() noexcept;
304
305private:
306 kernel_pid_t m_handle;
307 std::unique_ptr<thread_data, thread_data_deleter> m_data;
308};
309
315void swap(thread& lhs, thread& rhs) noexcept;
316
318template <class Tuple>
319void* thread_proxy(void* vp) {
320 { // without this scope, the objects here are not cleaned up correctly
321 std::unique_ptr<Tuple> p(static_cast<Tuple*>(vp));
322 auto tmp = std::get<0>(*p);
323 std::unique_ptr<thread_data, thread_data_deleter> data{tmp};
324 // create indices for the arguments, 0 is thread_data and 1 is the function
325 auto indices = detail::get_indices<std::tuple_size<Tuple>::value, 2>();
326 try {
327 detail::apply_args(std::get<1>(*p), indices, *p);
328 }
329 catch (...) {
330 // nop
331 }
332 if (data->joining_thread != KERNEL_PID_UNDEF) {
333 thread_wakeup(data->joining_thread);
334 }
335 }
336 // some riot cleanup code
338 return nullptr;
339}
342template <class F, class... Args>
343thread::thread(F&& f, Args&&... args) : m_data{new thread_data} {
344 using namespace std;
345 using func_and_args = tuple
346 <thread_data*, typename decay<F>::type, typename decay<Args>::type...>;
347 unique_ptr<func_and_args> p(
348 new func_and_args(m_data.get(), std::forward<F>(f), std::forward<Args>(args)...));
349 m_handle = thread_create(
350 m_data->stack.data(), m_data->stack.size(), THREAD_PRIORITY_MAIN - 1, 0,
351 &thread_proxy<func_and_args>, p.get(), "riot_cpp_thread");
352 if (m_handle >= 0) {
353 p.release();
354 } else {
355 throw std::system_error(
356 std::make_error_code(std::errc::resource_unavailable_try_again),
357 "Failed to create thread.");
358 }
359}
360
361inline thread& thread::operator=(thread&& other) noexcept {
362 if (m_handle != KERNEL_PID_UNDEF) {
363 std::terminate();
364 }
365 m_handle = other.m_handle;
366 other.m_handle = KERNEL_PID_UNDEF;
367 std::swap(m_data, other.m_data);
368 return *this;
369}
370
371inline void swap(thread& lhs, thread& rhs) noexcept { lhs.swap(rhs); }
372
373} // namespace riot
374
375#endif // RIOT_THREAD_HPP
C++11 chrono drop in replacement that adds the function now based on ztimer/timex.
implementation of thread::id
Definition thread.hpp:84
bool operator>(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:128
thread_id() noexcept
Creates a uninitialized thread id.
Definition thread.hpp:95
bool operator!=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:110
friend std::basic_ostream< T, Traits > & operator<<(std::basic_ostream< T, Traits > &out, thread_id id)
Enable printing of thread ids using output streams.
Definition thread.hpp:146
bool operator>=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:134
bool operator<(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:116
bool operator==(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:104
bool operator<=(thread_id other) noexcept
Comparison operator for thread ids.
Definition thread.hpp:122
thread_id(kernel_pid_t handle)
Create a thread id from a native handle.
Definition thread.hpp:99
C++11 compliant implementation of thread, however uses the time point from out chrono header instead ...
Definition thread.hpp:214
id get_id() const noexcept
Returns the id of a thread.
Definition thread.hpp:292
bool joinable() const noexcept
Query if the thread is joinable.
Definition thread.hpp:275
thread(const thread &)=delete
Disallow copy constructor.
static unsigned hardware_concurrency() noexcept
Returns the number of concurrent threads supported by the underlying hardware.
native_handle_type native_handle() noexcept
Returns the native handle to a thread.
Definition thread.hpp:296
thread & operator=(const thread &)=delete
Disallow copy assignment operator.
kernel_pid_t native_handle_type
The native handle type is the kernel_pid_t of RIOT.
Definition thread.hpp:223
thread() noexcept
Per default, an uninitialized thread is created.
Definition thread.hpp:228
void join()
Block until the thread finishes.
void swap(thread &t) noexcept
Swap threads.
Definition thread.hpp:266
void detach()
Detaches a thread from its handle and allows it to execute independently.
thread(thread &&t) noexcept
Move constructor.
Definition thread.hpp:245
A time point for timed wait, as clocks from the standard are not available on RIOT.
Definition chrono.hpp:41
C++11 condition variable drop in replacement.
int16_t kernel_pid_t
Unique process identifier.
Definition sched.h:139
NORETURN void sched_task_exit(void)
Removes thread from scheduler and set status to STATUS_STOPPED.
#define KERNEL_PID_UNDEF
Canonical identifier for an invalid PID.
Definition sched.h:110
kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority, int flags, thread_task_func_t task_func, void *arg, const char *name)
Creates a new thread.
void thread_yield(void)
Lets current thread yield.
int thread_wakeup(kernel_pid_t pid)
Wakes up a sleeping thread.
static kernel_pid_t thread_getpid(void)
Returns the process ID of the currently running thread.
Definition thread.h:393
C++11 mutex drop in replacement.
RIOT C++ namespace.
Definition chrono.hpp:35
time_point now()
Returns the current time saved in a time point.
Definition chrono.hpp:104
void swap(unique_lock< Mutex > &lhs, unique_lock< Mutex > &rhs) noexcept
Swaps two mutexes.
Definition mutex.hpp:309
This deleter prevents our thread data from being destroyed if the thread object is destroyed before t...
Definition thread.hpp:66
void operator()(thread_data *ptr)
Called by the deleter of a thread object to manage the lifetime of the thread internal management dat...
Definition thread.hpp:71
Holds context data for the thread.
Definition thread.hpp:51
#define THREAD_PRIORITY_MAIN
Priority of the main thread.
utility functions