ORIGINAL
Loading...
Searching...
No Matches
thread.h
Go to the documentation of this file.
1#ifndef THREAD_H
2#define THREAD_H
3
4#include "error.h"
5#include "functional"
6#include "pthread.h"
7#include "ownerPtr.h"
8
9
37
38namespace original {
49 class threadBase {
50 protected:
56 template<typename Callback>
58 {
59 Callback c;
60 public:
66 explicit threadData(Callback c);
67
75 static void* run(void* arg);
76 };
77
78 bool is_joinable;
79
84 [[nodiscard]] virtual bool valid() const = 0;
85
90 explicit threadBase(bool is_joinable = false);
91 public:
96 virtual ~threadBase() noexcept(false);
97
98 threadBase(const threadBase&) = delete;
99 threadBase& operator=(const threadBase&) = delete;
100
101 threadBase(threadBase&& other) noexcept = default;
102 threadBase& operator=(threadBase&& other) noexcept = default;
103
108 explicit operator bool() const;
109
114 bool operator!() const;
115
120 [[nodiscard]] bool joinable() const;
121 };
122
128 class pThread final : public threadBase {
129 pthread_t handle;
130
131 [[nodiscard]] bool valid() const override;
132 public:
136 explicit pThread();
137
146 template<typename Callback, typename... ARGS>
147 explicit pThread(Callback c, ARGS&&... args);
148
149 pThread(pThread&& other) noexcept;
150 pThread& operator=(pThread&& other) noexcept;
151
156 void join();
157
162 void detach();
163 };
164
170 class thread {
171 pThread thread_;
172 bool will_join;
173 public:
177 explicit thread();
178
187 template<typename Callback, typename... ARGS>
188 explicit thread(Callback c, ARGS&&... args);
189
198 template<typename Callback, typename... ARGS>
199 explicit thread(Callback c, bool will_join, ARGS&&... args);
200
206 explicit thread(pThread p_thread, bool will_join = true);
207
208 thread(const thread&) = delete;
209 thread& operator=(const thread&) = delete;
210
216 thread(thread&& other) noexcept;
217
223 thread(thread&& other, bool will_join) noexcept;
224
225 thread& operator=(thread&& other) noexcept;
226
231 [[nodiscard]] bool joinable() const;
232
237 explicit operator bool() const;
238
243 bool operator!() const;
244
249 void join();
250
255 void detach();
256
261 ~thread();
262 };
263}
264
265
266template <typename Callback>
269
270template <typename Callback>
272{
273 auto self = ownerPtr<threadData>(static_cast<threadData*>(arg));
274 try {
275 self->c();
276 }catch (const error&) {
277 throw sysError();
278 }
279 return nullptr;
280}
281
282inline original::threadBase::operator bool() const
283{
284 return this->valid();
285}
286
288{
289 return !this->valid();
290}
291
293 return this->is_joinable;
294}
295
296inline original::threadBase::threadBase(bool is_joinable)
297 : is_joinable(is_joinable) {}
298
299inline original::threadBase::~threadBase() noexcept(false) {
300 if (this->is_joinable) {
301 throw sysError();
302 }
303}
304
305inline original::pThread::pThread() : handle() {}
306
307template<typename Callback, typename... ARGS>
308original::pThread::pThread(Callback c, ARGS&&... args) : threadBase(true), handle()
309{
310 auto bound_lambda =
311 [func = std::forward<Callback>(c), ...lambda_args = std::forward<ARGS>(args)]() mutable {
312 std::invoke(std::move(func), std::move(lambda_args)...);
313 };
314
315 using bound_callback = decltype(bound_lambda);
316 using bound_thread_data = threadData<bound_callback>;
317
318 auto task = new bound_thread_data(std::move(bound_lambda));
319
320 if (const int code = pthread_create(&this->handle, nullptr, &bound_thread_data::run, task); code != 0)
321 {
322 throw sysError();
323 }
324}
325
326inline bool original::pThread::valid() const
327{
328 return this->handle != pthread_t{};
329}
330
331inline original::pThread::pThread(pThread&& other) noexcept
332 : threadBase(std::move(other)), handle() {
333 this->operator=(std::move(other));
334}
335
336inline original::pThread& original::pThread::operator=(pThread&& other) noexcept
337{
338 if (this == &other) {
339 return *this;
340 }
341
342 if (this->is_joinable && this->valid()) {
343 pthread_detach(this->handle);
344 }
345
346 this->handle = other.handle;
347 other.handle = {};
348 this->is_joinable = other.is_joinable;
349 other.is_joinable = false;
350 return *this;
351}
352
354 if (this->is_joinable){
355 if (const int code = pthread_join(this->handle, nullptr);
356 code != 0){
357 throw sysError();
358 }
359 this->is_joinable = false;
360 this->handle = {};
361 }
362}
363
365 if (this->is_joinable){
366 if (const int code = pthread_detach(this->handle);
367 code != 0){
368 throw sysError();
369 }
370 this->is_joinable = false;
371 this->handle = {};
372 }
373}
374
376 : will_join(true) {}
377
378template <typename Callback, typename ... ARGS>
379original::thread::thread(Callback c, ARGS&&... args)
380 : thread_(std::forward<Callback>(c), std::forward<ARGS>(args)...), will_join(true) {}
381
382template <typename Callback, typename ... ARGS>
383original::thread::thread(Callback c, const bool will_join, ARGS&&... args)
384 : thread_(std::forward<Callback>(c), std::forward<ARGS>(args)...), will_join(will_join) {}
385
386inline original::thread::thread(pThread p_thread, const bool will_join)
387 : thread_(std::move(p_thread)), will_join(will_join) {}
388
389inline original::thread::thread(thread&& other) noexcept
390 : thread_(std::move(other.thread_)), will_join(true) {}
391
392inline original::thread::thread(thread&& other, const bool will_join) noexcept
393 : thread_(std::move(other.thread_)), will_join(will_join) {}
394
395inline original::thread& original::thread::operator=(thread&& other) noexcept {
396 if (this == &other) {
397 return *this;
398 }
399
400 this->thread_ = std::move(other.thread_);
401 this->will_join = other.will_join;
402 other.will_join = false;
403 return *this;
404}
405
407{
408 this->thread_.join();
409}
410
412{
413 this->thread_.detach();
414}
415
417{
418 if (this->thread_.joinable()) {
419 this->will_join ? this->thread_.join() : this->thread_.detach();
420 }
421}
422
424 return this->thread_.joinable();
425}
426
427original::thread::operator bool() const {
428 return this->thread_.operator bool();
429}
430
432 return this->thread_.operator!();
433}
434
435#endif //THREAD_H
Base interface for all exception types in Original.
Definition error.h:50
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:30
POSIX thread implementation.
Definition thread.h:128
void detach()
Detach thread (allow it to run independently)
Definition thread.h:364
void join()
Wait for thread to complete.
Definition thread.h:353
pThread()
Construct empty (invalid) thread.
Definition thread.h:305
Definition error.h:193
Wrapper for thread execution data.
Definition thread.h:58
threadData(Callback c)
Construct thread data wrapper.
Definition thread.h:267
static void * run(void *arg)
Thread entry point wrapper.
Definition thread.h:271
Base class for thread implementations.
Definition thread.h:49
virtual bool valid() const =0
Check if thread is valid.
virtual ~threadBase() noexcept(false)
Destructor.
Definition thread.h:299
threadBase(bool is_joinable=false)
Construct thread base.
Definition thread.h:296
bool joinable() const
Check if thread is joinable.
Definition thread.h:292
bool operator!() const
Check if thread is not valid.
Definition thread.h:287
High-level thread wrapper.
Definition thread.h:170
~thread()
Destructor.
Definition thread.h:416
void detach()
Detach thread (allow it to run independently)
Definition thread.h:411
bool operator!() const
Check if thread is not valid.
Definition thread.h:431
thread()
Construct empty thread.
Definition thread.h:375
bool joinable() const
Check if thread is joinable.
Definition thread.h:423
void join()
Wait for thread to complete.
Definition thread.h:406
Custom exception classes and callback validation utilities.
Main namespace for the project Original.
Definition algorithms.h:21
Exclusive-ownership smart pointer implementation.