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#include "zeit.h"
9
10
21namespace original {
35 template <typename DERIVED>
36 class threadBase : public comparable<DERIVED>,
37 public hashable<DERIVED>,
38 public printable {
39 protected:
47 template<typename Callback>
49 {
50 Callback c;
51 public:
57 explicit threadData(Callback c);
58
67 static void* run(void* arg);
68 };
69
75 [[nodiscard]] virtual bool valid() const = 0;
76
82 [[nodiscard]] virtual ul_integer id() const = 0;
83 public:
84
89 explicit threadBase() noexcept = default;
90
95 ~threadBase() noexcept override = default;
96
97 threadBase(const threadBase&) = delete;
98 threadBase& operator=(const threadBase&) = delete;
99
100 threadBase(threadBase&& other) noexcept = default;
101 threadBase& operator=(threadBase&& other) noexcept = default;
102
107 explicit operator bool() const;
108
113 bool operator!() const;
114
121 [[nodiscard]] virtual bool joinable() const = 0;
122
128 virtual void join() = 0;
129
136 virtual void detach() = 0;
137
138 std::string className() const override;
139
140 std::string toString(bool enter) const override;
141 };
142
152 class pThread final : public threadBase<pThread> {
153 pthread_t handle;
154 bool is_joinable;
155
160 [[nodiscard]] bool valid() const override;
161 public:
166 explicit pThread();
167
177 template<typename Callback, typename... ARGS>
178 explicit pThread(Callback c, ARGS&&... args);
179
185 pThread(pThread&& other) noexcept;
186
193 pThread& operator=(pThread&& other) noexcept;
194
199 [[nodiscard]] ul_integer id() const override;
200
206 [[nodiscard]] bool joinable() const override;
207
208 integer compareTo(const pThread &other) const override;
209
210 u_integer toHash() const noexcept override;
211
212 std::string className() const override;
213
219 void join() override;
220
226 void detach() override;
227
232 ~pThread() override;
233 };
234
263 class thread final : public threadBase<thread> {
264 pThread thread_;
265 bool will_join;
266
279 enum class joinPolicy {
280 AUTO_JOIN,
281 AUTO_DETACH,
282 };
283
284 [[nodiscard]] bool valid() const override;
285 public:
286
287 static ul_integer thisId();
288
299 static inline void sleep(const time::duration& d);
300
302 static constexpr auto AUTO_JOIN = joinPolicy::AUTO_JOIN;
303
305 static constexpr auto AUTO_DETACH = joinPolicy::AUTO_DETACH;
306
311 explicit thread();
312
321 template<typename Callback, typename... ARGS>
322 explicit thread(Callback c, ARGS&&... args);
323
335 template<typename Callback, typename... ARGS>
336 explicit thread(Callback c, joinPolicy policy, ARGS&&... args);
337
344 explicit thread(pThread p_thread, joinPolicy policy = AUTO_JOIN);
345
346 thread(const thread&) = delete;
347 thread& operator=(const thread&) = delete;
348
354 thread(thread&& other) noexcept;
355
362 thread(thread&& other, joinPolicy policy) noexcept;
363
370 thread& operator=(thread&& other) noexcept;
371
376 [[nodiscard]] ul_integer id() const override;
377
383 [[nodiscard]] bool joinable() const override;
384
385 integer compareTo(const thread &other) const override;
386
387 u_integer toHash() const noexcept override;
388
389 std::string className() const override;
390
396 void join() override;
397
403 void detach() override;
404
410 ~thread() override;
411 };
412}
413
414
415template <typename DERIVED>
416template <typename Callback>
417original::threadBase<DERIVED>::threadData<Callback>::threadData(Callback c)
418 : c(std::move(c)) {}
419
420template <typename DERIVED>
421template <typename Callback>
423{
424 auto self = ownerPtr<threadData>(static_cast<threadData*>(arg));
425 try {
426 self->c();
427 }catch (const error&) {
428 throw sysError("Thread callback execution failed");
429 }
430 return nullptr;
431}
432
433template <typename DERIVED>
435{
436 return this->valid();
437}
438
439template <typename DERIVED>
441{
442 return !this->valid();
443}
444
445template<typename DERIVED>
447 return "threadBase";
448}
449
450template<typename DERIVED>
451std::string original::threadBase<DERIVED>::toString(bool enter) const {
452 std::stringstream ss;
453 ss << "(" << this->className() << " ";
454 ss << "#" << this->id();
455 ss << ")";
456 if (enter)
457 ss << "\n";
458 return ss.str();
459}
460
461inline original::pThread::pThread() : handle(), is_joinable() {}
462
463template<typename Callback, typename... ARGS>
464original::pThread::pThread(Callback c, ARGS&&... args) : handle(), is_joinable(true)
465{
466 auto bound_lambda =
467 [func = std::forward<Callback>(c), ...lambda_args = std::forward<ARGS>(args)]() mutable {
468 std::invoke(std::move(func), std::move(lambda_args)...);
469 };
470
471 using bound_callback = decltype(bound_lambda);
472 using bound_thread_data = threadData<bound_callback>;
473
474 auto task = new bound_thread_data(std::move(bound_lambda));
475
476 if (const int code = pthread_create(&this->handle, nullptr, &bound_thread_data::run, task); code != 0)
477 {
478 delete task;
479 throw sysError("Failed to create thread (pthread_create returned " + formatString(code) + ")");
480 }
481}
482
483inline bool original::pThread::valid() const
484{
485 return this->handle != pthread_t{};
486}
487
488inline original::pThread::pThread(pThread&& other) noexcept
489 : pThread() {
490 this->operator=(std::move(other));
491}
492
494{
495 if (this == &other) {
496 return *this;
497 }
498
499 if (this->is_joinable && this->valid()) {
500 pthread_detach(this->handle);
501 }
502
503 this->handle = other.handle;
504 other.handle = {};
505 this->is_joinable = other.is_joinable;
506 other.is_joinable = false;
507 return *this;
508}
509
511 ul_integer id = 0;
512 std::memcpy(&id, &this->handle, sizeof(pthread_t));
513 return id;
514}
515
517{
518 return this->is_joinable;
519}
520
522original::pThread::compareTo(const pThread& other) const {
523 if (this->id() != other.id())
524 return this->id() > other.id() ? 1 : -1;
525 return 0;
526}
527
530 return hash<pThread>::hashFunc(this->id());
531}
532
533inline std::string original::pThread::className() const {
534 return "pThread";
535}
536
538 if (this->is_joinable){
539 if (const int code = pthread_join(this->handle, nullptr);
540 code != 0){
541 throw sysError("Failed to join thread (pthread_join returned " + formatString(code) + ")");
542 }
543 this->is_joinable = false;
544 this->handle = {};
545 }
546}
547
549 if (this->is_joinable){
550 if (const int code = pthread_detach(this->handle);
551 code != 0){
552 throw sysError("Failed to detach thread (pthread_detach returned " + formatString(code) + ")");
553 }
554 this->is_joinable = false;
555 this->handle = {};
556 }
557}
558
560{
561 if (this->is_joinable) {
562 try {
563 this->detach();
564 } catch (...) {
565 std::cerr << "Fatal error in pThread destructor" << std::endl;
566 std::terminate();
567 }
568 }
569}
570
571inline bool original::thread::valid() const
572{
573 return this->thread_.operator bool();
574}
575
577original::thread::thisId() {
578 ul_integer id = 0;
579#ifdef ORIGINAL_COMPILER_GCC
580 auto handle = pthread_self();
581 std::memcpy(&id, &handle, sizeof(pthread_t));
582#endif
583 return id;
584}
585
587{
588 if (d.value() < 0)
589 return;
590
591#ifdef ORIGINAL_COMPILER_GCC
592 const auto deadline = time::point::now() + d;
593 const auto ts = deadline.toTimespec();
594 int ret;
595
596 while (true) {
597 if (ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, nullptr)
598 ; ret == 0) break;
599 if (errno == EINTR) continue;
600 if (errno == EINVAL) {
601 if (time::point::now() >= deadline) return;
602 }
603 throw sysError("Failed to sleep thread (clock_nano-sleep returned " + formatString(ret) +
604 ", errno: " + std::to_string(errno) + ")");
605 }
606#else
607 ::Sleep(static_cast<DWORD>((d.value() + time::FACTOR_MILLISECOND - 1) / time::FACTOR_MILLISECOND));
608#endif
609}
610
612 : will_join(true) {}
613
614template <typename Callback, typename ... ARGS>
615original::thread::thread(Callback c, ARGS&&... args)
616 : thread_(std::forward<Callback>(c), std::forward<ARGS>(args)...), will_join(true) {}
617
618template <typename Callback, typename ... ARGS>
619original::thread::thread(Callback c, const joinPolicy policy, ARGS&&... args)
620 : thread_(std::forward<Callback>(c), std::forward<ARGS>(args)...), will_join(policy == AUTO_JOIN) {}
621
622inline original::thread::thread(pThread p_thread, const joinPolicy policy)
623 : thread_(std::move(p_thread)), will_join(policy == AUTO_JOIN) {}
624
625inline original::thread::thread(thread&& other) noexcept
626 : thread_(std::move(other.thread_)), will_join(true) {}
627
628inline original::thread::thread(thread&& other, const joinPolicy policy) noexcept
629 : thread_(std::move(other.thread_)), will_join(policy == AUTO_JOIN) {}
630
632 if (this == &other) {
633 return *this;
634 }
635
636 this->thread_ = std::move(other.thread_);
637 this->will_join = other.will_join;
638 other.will_join = false;
639 return *this;
640}
641
643original::thread::compareTo(const thread& other) const {
644 return this->thread_.compareTo(other.thread_);
645}
646
648original::thread::toHash() const noexcept {
649 return this->thread_.toHash();
650}
651
652inline std::string original::thread::className() const {
653 return "thread";
654}
655
657{
658 this->thread_.join();
659}
660
662{
663 this->thread_.detach();
664}
665
667{
668 try {
669 this->will_join ? this->thread_.join() : this->thread_.detach();
670 } catch (const sysError& e) {
671 std::cerr << "Fatal error in thread destructor: " << e.what() << std::endl;
672 std::terminate();
673 }
674}
675
677 return this->thread_.id();
678}
679
680inline bool original::thread::joinable() const
681{
682 return this->thread_.joinable();
683}
684
685#endif //THREAD_H
Base class for comparable objects.
Definition comparable.h:31
virtual integer compareTo(const DERIVED &other) const =0
Compares the current object with another of the same type.
Base class for all exceptions in the Original project.
Definition error.h:53
const char * what() const noexcept override
Returns the full error message.
Definition error.h:92
static u_integer hashFunc(const T &t) noexcept
Default hash function fallback.
Forward declaration of hashable interface template.
Definition hash.h:240
virtual u_integer toHash() const noexcept
Computes the hash of the object.
Definition hash.h:367
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
POSIX thread implementation.
Definition thread.h:152
std::string className() const override
Gets the class name for type identification.
Definition thread.h:533
void join() override
Wait for thread to complete.
Definition thread.h:537
pThread & operator=(pThread &&other) noexcept
Move assignment.
Definition thread.h:493
void detach() override
Detach thread (allow it to run independently)
Definition thread.h:548
u_integer toHash() const noexcept override
Computes the hash of the object.
Definition thread.h:529
ul_integer id() const override
Get thread identifier.
Definition thread.h:510
~pThread() override
Destructor.
Definition thread.h:559
pThread()
Construct empty (invalid) thread.
Definition thread.h:461
bool joinable() const override
Check if thread is joinable.
Definition thread.h:516
Base class providing polymorphic string conversion capabilities.
Definition printable.h:39
static std::string formatString(const TYPE &t)
Universal value-to-string conversion.
Definition printable.h:263
Exception for generic system failure.
Definition error.h:306
Concrete task implementation with result type.
Definition tasks.h:43
Wrapper for thread execution data.
Definition thread.h:49
static void * run(void *arg)
Thread entry point wrapper.
Definition thread.h:422
Base class for thread implementations.
Definition thread.h:38
std::string toString(bool enter) const override
Generates formatted string representation.
Definition thread.h:451
virtual ul_integer id() const =0
Get thread identifier.
virtual void join()=0
Wait for thread to complete execution.
virtual bool valid() const =0
Check if thread is valid.
bool operator!() const
Check if thread is not valid.
Definition thread.h:440
std::string className() const override
Gets the class name for type identification.
Definition thread.h:446
threadBase & operator=(const threadBase &)=delete
Deleted copy assignment.
threadBase() noexcept=default
Default constructor.
virtual void detach()=0
Detach thread from handle.
virtual bool joinable() const =0
Check if thread is joinable.
High-level thread wrapper.
Definition thread.h:263
static void sleep(const time::duration &d)
Puts the current thread to sleep for a specified duration.
Definition thread.h:586
void detach() override
Detach thread (allow it to run independently)
Definition thread.h:661
void join() override
Wait for thread to complete.
Definition thread.h:656
thread & operator=(const thread &)=delete
Deleted copy assignment.
thread(const thread &)=delete
Deleted copy constructor.
bool joinable() const override
Check if thread is joinable.
Definition thread.h:680
thread()
Construct empty thread.
Definition thread.h:611
ul_integer id() const override
Get thread identifier.
Definition thread.h:676
u_integer toHash() const noexcept override
Computes the hash of the object.
Definition thread.h:648
~thread() override
Destructor.
Definition thread.h:666
std::string className() const override
Gets the class name for type identification.
Definition thread.h:652
Represents a time duration with nanosecond precision.
Definition zeit.h:134
time_val_type value(unit unit=MILLISECOND) const
Gets the duration value in specified units.
Definition zeit.h:1127
static point now()
Gets current time point.
Definition zeit.h:1352
static constexpr time_val_type FACTOR_MILLISECOND
Conversion factor for milliseconds.
Definition zeit.h:95
Custom exception classes and callback validation utilities.
std::uint32_t u_integer
32-bit unsigned integer type for sizes and indexes
Definition config.h:263
std::uint64_t ul_integer
64-bit unsigned integer type
Definition config.h:274
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:254
Main namespace for the project Original.
Definition algorithms.h:21
Exclusive-ownership smart pointer implementation.
Time and date handling utilities.