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 "config.h"
5
6#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
7#include "pthread.h"
8#elif ORIGINAL_COMPILER_MSVC
9#ifndef WIN32_LEAN_AND_MEAN
10#define WIN32_LEAN_AND_MEAN
11#endif
12#endif
13
14#include "error.h"
15#include "functional"
16#include "hash.h"
17#include "ownerPtr.h"
18#include "zeit.h"
19
20
31namespace original {
45 template <typename DERIVED>
46 class threadBase : public comparable<DERIVED>,
47 public hashable<DERIVED>,
48 public printable {
49 protected:
57 template<typename Callback>
59 {
60 Callback c;
61 public:
67 explicit threadData(Callback c);
68
77 static void* run(void* arg);
78 };
79
85 [[nodiscard]] virtual bool valid() const = 0;
86
92 [[nodiscard]] virtual ul_integer id() const = 0;
93 public:
94
100
106
109
112
118
124
132
138 virtual void join() = 0;
139
146 virtual void detach() = 0;
147
149
151 };
152
153#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
163 class pThread final : public threadBase<pThread> {
164 pthread_t handle;
165 bool is_joinable;
166
171 [[nodiscard]] bool valid() const override;
172 public:
177 explicit pThread();
178
188 template<typename Callback, typename... ARGS>
189 explicit pThread(Callback c, ARGS&&... args);
190
196 pThread(pThread&& other) noexcept;
197
204 pThread& operator=(pThread&& other) noexcept;
205
210 [[nodiscard]] ul_integer id() const override;
211
217 [[nodiscard]] bool joinable() const override;
218
219 integer compareTo(const pThread &other) const override;
220
221 u_integer toHash() const noexcept override;
222
223 std::string className() const override;
224
230 void join() override;
231
237 void detach() override;
238
243 ~pThread() override;
244 };
245#elif ORIGINAL_COMPILER_MSVC
246 class wThread final : public threadBase<wThread> {
247 HANDLE handle;
248 bool is_joinable;
249
250 [[nodiscard]] bool valid() const override;
251 public:
252 explicit wThread();
253
254 template<typename Callback, typename... ARGS>
255 explicit wThread(Callback c, ARGS&&... args...);
256
257 wThread(wThread&& other) noexcept;
258
259 wThread& operator=(wThread&& other) noexcept;
260
261 [[nodiscard]] ul_integer id() const override;
262
263 [[nodiscard]] bool joinable() const override;
264
265 integer compareTo(const wThread &other) const override;
266
268
269 std::string className() const override;
270
271 void join() override;
272
273 void detach() override;
274
275 ~wThread() override;
276 };
277#endif
278
307 class thread final : public threadBase<thread> {
308 #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
310 #elif ORIGINAL_COMPILER_MSVC
312 #endif
313 bool will_join;
314
327 enum class joinPolicy {
328 AUTO_JOIN,
329 AUTO_DETACH,
330 };
331
332 [[nodiscard]] bool valid() const override;
333 public:
334
335 static ul_integer thisId();
336
347 static inline void sleep(const time::duration& d);
348
350 static constexpr auto AUTO_JOIN = joinPolicy::AUTO_JOIN;
351
353 static constexpr auto AUTO_DETACH = joinPolicy::AUTO_DETACH;
354
359 explicit thread();
360
369 template<typename Callback, typename... ARGS>
370 explicit thread(Callback c, ARGS&&... args);
371
383 template<typename Callback, typename... ARGS>
384 explicit thread(Callback c, joinPolicy policy, ARGS&&... args);
385
386#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
393 explicit thread(pThread p_thread, joinPolicy policy = AUTO_JOIN);
394#elif ORIGINAL_COMPILER_MSVC
395 explicit thread(wThread w_thread, joinPolicy policy = AUTO_JOIN);
396#endif
397
398 thread(const thread&) = delete;
399 thread& operator=(const thread&) = delete;
400
406 thread(thread&& other) noexcept;
407
414 thread(thread&& other, joinPolicy policy) noexcept;
415
422 thread& operator=(thread&& other) noexcept;
423
428 [[nodiscard]] ul_integer id() const override;
429
435 [[nodiscard]] bool joinable() const override;
436
437 [[nodiscard]] integer compareTo(const thread &other) const override;
438
440
441 [[nodiscard]] std::string className() const override;
442
448 void join() override;
449
455 void detach() override;
456
462 ~thread() override;
463 };
464}
465
466
471
472template <typename DERIVED>
473template <typename Callback>
475{
476 auto self = ownerPtr<threadData>(static_cast<threadData*>(arg));
477 try {
478 self->c();
479 }catch (const error& e) {
480 throw sysError("Thread callback execution failed with message: " + e.message());
481 }
482 return nullptr;
483}
484
485template <typename DERIVED>
487{
488 return this->valid();
489}
490
491template <typename DERIVED>
493{
494 return !this->valid();
495}
496
497template<typename DERIVED>
499 return "threadBase";
500}
501
502template<typename DERIVED>
504 std::stringstream ss;
505 ss << "(" << this->className() << " ";
506 ss << "#" << this->id();
507 ss << ")";
508 if (enter)
509 ss << "\n";
510 return ss.str();
511}
512#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
513inline original::pThread::pThread() : handle(), is_joinable() {}
514
515template<typename Callback, typename... ARGS>
516original::pThread::pThread(Callback c, ARGS&&... args) : handle(), is_joinable(true)
517{
518 auto bound_lambda =
519 [func = std::forward<Callback>(c), ...lambda_args = std::forward<ARGS>(args)]() mutable {
520 std::invoke(std::move(func), std::move(lambda_args)...);
521 };
522
523 using bound_callback = decltype(bound_lambda);
524 using bound_thread_data = threadData<bound_callback>;
525
526 auto task = new bound_thread_data(std::move(bound_lambda));
527
528 if (const int code = pthread_create(&this->handle, nullptr, &bound_thread_data::run, task); code != 0)
529 {
530 delete task;
531 throw sysError("Failed to create thread (pthread_create returned " + formatString(code) + ")");
532 }
533}
534
535inline bool original::pThread::valid() const
536{
537 return this->handle != pthread_t{};
538}
539
540inline original::pThread::pThread(pThread&& other) noexcept
541 : pThread() {
542 this->operator=(std::move(other));
543}
544
545inline original::pThread& original::pThread::operator=(pThread&& other) noexcept
546{
547 if (this == &other) {
548 return *this;
549 }
550
551 if (this->is_joinable && this->valid()) {
552 pthread_detach(this->handle);
553 }
554
555 this->handle = other.handle;
556 other.handle = {};
557 this->is_joinable = other.is_joinable;
558 other.is_joinable = false;
559 return *this;
560}
561
562inline original::ul_integer original::pThread::id() const {
563 ul_integer id = 0;
564 std::memcpy(&id, &this->handle, sizeof(pthread_t));
565 return id;
566}
567
568inline bool original::pThread::joinable() const
569{
570 return this->is_joinable;
571}
572
574original::pThread::compareTo(const pThread& other) const {
575 if (this->id() != other.id())
576 return this->id() > other.id() ? 1 : -1;
577 return 0;
578}
579
581original::pThread::toHash() const noexcept {
582 return hash<pThread>::hashFunc(this->id());
583}
584
585inline std::string original::pThread::className() const {
586 return "pThread";
587}
588
589inline void original::pThread::join() {
590 if (this->is_joinable){
591 if (const int code = pthread_join(this->handle, nullptr);
592 code != 0){
593 throw sysError("Failed to join thread (pthread_join returned " + formatString(code) + ")");
594 }
595 this->is_joinable = false;
596 this->handle = {};
597 }
598}
599
600inline void original::pThread::detach() {
601 if (this->is_joinable){
602 if (const int code = pthread_detach(this->handle);
603 code != 0){
604 throw sysError("Failed to detach thread (pthread_detach returned " + formatString(code) + ")");
605 }
606 this->is_joinable = false;
607 this->handle = {};
608 }
609}
610
611inline original::pThread::~pThread()
612{
613 if (this->is_joinable) {
614 try {
615 this->detach();
616 } catch (...) {
617 std::cerr << "Fatal error in pThread destructor" << std::endl;
618 std::terminate();
619 }
620 }
621}
622#elif ORIGINAL_COMPILER_MSVC
623inline bool original::wThread::valid() const
624{
625 return this->handle != HANDLE{};
626}
627
628inline original::wThread::wThread() : handle(), is_joinable() {}
629
630template <typename Callback, typename ... ARGS>
631original::wThread::wThread(Callback c, ARGS&&... args, ...) : handle(), is_joinable(true)
632{
633 auto bound_lambda =
634 [func = std::forward<Callback>(c), ...lambda_args = std::forward<ARGS>(args)]() mutable {
635 std::invoke(std::move(func), std::move(lambda_args)...);
636 };
637
638 using bound_callback = decltype(bound_lambda);
639 using bound_thread_data = threadData<bound_callback>;
640
641 auto task = new bound_thread_data(std::move(bound_lambda));
642
643 static auto threadEntry = [](LPVOID param) -> DWORD {
644 bound_thread_data::run(param);
645 return 0;
646 };
647
648 this->handle = CreateThread(nullptr, 0, threadEntry, task, 0, nullptr);
649 if (this->handle == nullptr) {
650 delete task;
651 throw sysError("Failed to create thread (CreateThread returned null)");
652 }
653}
654
655inline original::wThread::wThread(wThread&& other) noexcept : wThread()
656{
657 this->operator=(std::move(other));
658}
659
660inline original::wThread& original::wThread::operator=(wThread&& other) noexcept
661{
662 if (this == &other) {
663 return *this;
664 }
665
666 if (this->is_joinable && this->valid()) {
667 CloseHandle(this->handle);
668 }
669
670 this->handle = other.handle;
671 other.handle = {};
672 this->is_joinable = other.is_joinable;
673 other.is_joinable = false;
674 return *this;
675}
676
677inline original::ul_integer original::wThread::id() const
678{
679 ul_integer id = 0;
680 std::memcpy(&id, &this->handle, sizeof(HANDLE));
681 return id;
682}
683
684inline bool original::wThread::joinable() const
685{
686 return this->is_joinable;
687}
688
689inline original::integer original::wThread::compareTo(const wThread& other) const
690{
691 if (this->id() != other.id())
692 return this->id() > other.id() ? 1 : -1;
693 return 0;
694}
695
696inline original::u_integer original::wThread::toHash() const noexcept
697{
698 return hash<HANDLE>::hashFunc(this->id());
699}
700
701inline std::string original::wThread::className() const
702{
703 return "wThread";
704}
705
706inline void original::wThread::join()
707{
708 WaitForSingleObject(this->handle, INFINITE);
709 this->is_joinable = false;
710 this->handle = {};
711}
712
713inline void original::wThread::detach()
714{
715 CloseHandle(this->handle);
716 this->is_joinable = false;
717 this->handle = {};
718}
719
720inline original::wThread::~wThread()
721{
722 if (this->is_joinable) {
723 try {
724 this->detach();
725 } catch (...) {
726 std::cerr << "Fatal error in wThread destructor" << std::endl;
727 std::terminate();
728 }
729 }
730}
731#endif
732
733inline bool original::thread::valid() const
734{
735 return this->thread_.operator bool();
736}
737
739original::thread::thisId() {
740 ul_integer id = 0;
741#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
742 auto handle = pthread_self();
743 std::memcpy(&id, &handle, sizeof(pthread_t));
744#elif ORIGINAL_COMPILER_MSVC
745 const auto handle = GetCurrentThreadId();
746 std::memcpy(&id, &handle, sizeof(HANDLE));
747#endif
748 return id;
749}
750
752{
753 if (d.value() < 0)
754 return;
755
756#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
757 const auto deadline = time::point::now() + d;
758 const auto ts = deadline.toTimespec();
759 int ret;
760
761 while (true) {
763 ; ret == 0) break;
764 if (errno == EINTR) continue;
765 if (errno == EINVAL) {
766 if (time::point::now() >= deadline) return;
767 }
768 throw sysError("Failed to sleep thread (clock_nano-sleep returned " + formatString(ret) +
769 ", errno: " + std::to_string(errno) + ")");
770 }
771#elif ORIGINAL_COMPILER_MSVC
772 Sleep(d.toDWMilliseconds());
773#endif
774}
775
777 : will_join(true) {}
778
779template <typename Callback, typename ... ARGS>
782
783template <typename Callback, typename ... ARGS>
785 : thread_(std::forward<Callback>(c), std::forward<ARGS>(args)...), will_join(policy == AUTO_JOIN) {}
786
787#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
788inline original::thread::thread(pThread p_thread, const joinPolicy policy)
789 : thread_(std::move(p_thread)), will_join(policy == AUTO_JOIN) {}
790#elif ORIGINAL_COMPILER_MSVC
791inline original::thread::thread(wThread w_thread, const joinPolicy policy)
792 : thread_(std::move(w_thread)), will_join(policy == AUTO_JOIN) {}
793#endif
794
796 : thread_(std::move(other.thread_)), will_join(true) {}
797
799 : thread_(std::move(other.thread_)), will_join(policy == AUTO_JOIN) {}
800
802 if (this == &other) {
803 return *this;
804 }
805
806 this->thread_ = std::move(other.thread_);
807 this->will_join = other.will_join;
808 other.will_join = false;
809 return *this;
810}
811
813original::thread::compareTo(const thread& other) const {
814 return this->thread_.compareTo(other.thread_);
815}
816
819 return this->thread_.toHash();
820}
821
822inline std::string original::thread::className() const {
823 return "thread";
824}
825
827{
828 this->thread_.join();
829}
830
832{
833 this->thread_.detach();
834}
835
837{
838 try {
839 this->will_join ? this->thread_.join() : this->thread_.detach();
840 } catch (const sysError& e) {
841 std::cerr << "Fatal error in thread destructor: " << e.what() << std::endl;
842 std::terminate();
843 }
844}
845
847 return this->thread_.id();
848}
849
850inline bool original::thread::joinable() const
851{
852 return this->thread_.joinable();
853}
854
855#endif //THREAD_H
integer compareTo(const autoPtr &other) const override
Compare reference counters.
Definition autoPtr.h:714
u_integer toHash() const noexcept override
Compute hash value for the pointer.
Definition autoPtr.h:735
Base class for comparable objects.
Definition comparable.h:35
Base class for all exceptions in the Original project.
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:220
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
Base class providing polymorphic string conversion capabilities.
Definition printable.h:39
static std::string formatString(const TYPE &t)
Universal value-to-string conversion with type-specific formatting.
Definition printable.h:339
Exception for generic system failure.
Definition error.h:413
Wrapper for thread execution data.
Definition thread.h:59
static void * run(void *arg)
Thread entry point wrapper.
Definition thread.h:474
Base class for thread implementations.
Definition thread.h:48
std::string toString(bool enter) const override
Generates formatted string representation.
Definition thread.h:503
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:492
std::string className() const override
Gets the class name for type identification.
Definition thread.h:498
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:307
static void sleep(const time::duration &d)
Puts the current thread to sleep for a specified duration.
Definition thread.h:751
void detach() override
Detach thread (allow it to run independently)
Definition thread.h:831
void join() override
Wait for thread to complete.
Definition thread.h:826
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:850
thread()
Construct empty thread.
Definition thread.h:776
ul_integer id() const override
Get thread identifier.
Definition thread.h:846
u_integer toHash() const noexcept override
Computes the hash of the object.
Definition thread.h:818
~thread() override
Destructor.
Definition thread.h:836
std::string className() const override
Gets the class name for type identification.
Definition thread.h:822
Represents a time duration with nanosecond precision.
Definition zeit.h:143
static point now()
Gets current time point.
Definition zeit.h:1386
Platform-independent type definitions and compiler/platform detection.
Custom exception classes and callback validation utilities.
Provides a generic hashing utility and interface for hashable types.
Main namespace for the project Original.
Definition algorithms.h:21
coroutine::generator< T > join(coroutine::generator< T > gen1, coroutine::generator< U > gen2)
Joins two generators of compatible types.
Standard namespace extensions for original::alternative.
Definition allocator.h:351
std::string to_string(const T &t)
std::to_string overload for printable-derived types
Definition printable.h:415
Exclusive-ownership smart pointer implementation.
Time and date handling utilities.