ORIGINAL
Loading...
Searching...
No Matches
mutex.h
Go to the documentation of this file.
1#ifndef MUTEX_H
2#define MUTEX_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#endif
10
11#include "error.h"
12#include "tuple.h"
13#include "zeit.h"
14#include <iostream>
15
25namespace original {
37 class mutexBase {
38 public:
43 virtual void lock() = 0;
44
50 virtual bool tryLock() = 0;
51
56 virtual void unlock() = 0;
57
62 [[nodiscard]] virtual ul_integer id() const = 0;
63
65 explicit mutexBase() = default;
66
68 mutexBase(const mutexBase&) = delete;
69
71 mutexBase& operator=(const mutexBase&) = delete;
72
77 [[nodiscard]] virtual void* nativeHandle() noexcept = 0;
78
81 };
82
92 protected:
97 virtual void lock() = 0;
98
104 virtual bool tryLock() = 0;
105
110 virtual void unlock() = 0;
111
116 [[nodiscard]] virtual bool isLocked() const noexcept = 0;
117 public:
123 MANUAL_LOCK,
124 AUTO_LOCK,
125 TRY_LOCK,
126 ADOPT_LOCK,
127 };
128
130 static constexpr auto MANUAL_LOCK = lockPolicy::MANUAL_LOCK;
132 static constexpr auto AUTO_LOCK = lockPolicy::AUTO_LOCK;
134 static constexpr auto TRY_LOCK = lockPolicy::TRY_LOCK;
136 static constexpr auto ADOPT_LOCK = lockPolicy::ADOPT_LOCK;
137
139 explicit lockGuard() = default;
140
142 lockGuard(const lockGuard&) = delete;
143
145 lockGuard& operator=(const lockGuard&) = delete;
146
148 virtual ~lockGuard() = default;
149 };
150
151#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
160 class pMutex final : public mutexBase {
161 pthread_mutex_t mutex_{};
162 public:
164 using native_handle = pthread_mutex_t;
165
170 explicit pMutex();
171
173 pMutex(pMutex&&) = delete;
174
176 pMutex& operator=(pMutex&&) = delete;
177
182 [[nodiscard]] ul_integer id() const override;
183
188 [[nodiscard]] void* nativeHandle() noexcept override;
189
194 void lock() override;
195
201 bool tryLock() override;
202
207 void unlock() override;
208
213 ~pMutex() override;
214 };
215#elif ORIGINAL_COMPILER_MSVC
216 class wMutex final : public mutexBase {
217 SRWLOCK lock_;
218 public:
219 using native_handle = SRWLOCK;
220
221 explicit wMutex();
222
223 wMutex(wMutex&&) = delete;
224
225 wMutex& operator=(wMutex&&) = delete;
226
227 [[nodiscard]] ul_integer id() const override;
228
229 [[nodiscard]] void* nativeHandle() noexcept override;
230
231 void lock() override;
232
233 bool tryLock() override;
234
235 void unlock() override;
236
237 ~wMutex() override;
238 };
239#endif
240
241 class mutex final : public mutexBase {
242 #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
243 pMutex mutex_;
244 #elif ORIGINAL_COMPILER_MSVC
245 wMutex mutex_;
246 #endif
247
248 public:
249 using native_handle =
250 #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
251 pMutex::native_handle;
252 #elif ORIGINAL_COMPILER_MSVC
253 wMutex::native_handle;
254 #endif
255
256 mutex();
257
258 mutex(mutex&&) = delete;
259
260 mutex& operator=(mutex&) = delete;
261
262 [[nodiscard]] ul_integer id() const override;
263
264 [[nodiscard]] void* nativeHandle() noexcept override;
265
266 void lock() override;
267
268 bool tryLock() override;
269
270 void unlock() override;
271 };
272
280 class uniqueLock final : public lockGuard {
281 mutexBase& mutex_;
282 bool is_locked;
283
284 public:
291 explicit uniqueLock(mutexBase& mutex, lockPolicy policy = AUTO_LOCK);
292
295
298
303 [[nodiscard]] bool isLocked() const noexcept override;
304
309 void lock() override;
310
316 bool tryLock() override;
317
322 void unlock() override;
323
328 };
329
340 tuple<MUTEX* ...> m_list;
341 bool is_locked_all;
342
348 template<u_integer... IDXES>
349 void lockAll(indexSequence<IDXES...> sequence);
350
357 template<u_integer... IDXES>
358 bool tryLockAll(indexSequence<IDXES...> sequence);
359
365 template<u_integer... IDXES>
366 void unlockAll(indexSequence<IDXES...> sequence);
367 public:
372 explicit multiLock(MUTEX&... mutex);
373
379 explicit multiLock(lockPolicy policy, MUTEX&... mutex);
380
385 [[nodiscard]] bool isLocked() const noexcept override;
386
391 void lock() override;
392
398 bool tryLock() override;
399
404 void unlock() override;
405
407 multiLock(multiLock&&) = delete;
408
411
415 ~multiLock() override;
416 };
417}
418
419#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG
420inline original::pMutex::pMutex() : mutex_{} {
421 if (const int code = pthread_mutex_init(&this->mutex_, nullptr);
422 code != 0){
423 throw sysError("Failed to initialize mutex (pthread_mutex_init returned " + printable::formatString(code) + ")");
424 }
425}
426
427inline original::ul_integer original::pMutex::id() const {
428 return reinterpret_cast<ul_integer>(&this->mutex_);
429}
430
431inline void* original::pMutex::nativeHandle() noexcept
432{
433 return &this->mutex_;
434}
435
436inline void original::pMutex::lock() {
437 if (const int code = pthread_mutex_lock(&this->mutex_);
438 code != 0) {
439 throw sysError("Failed to lock mutex (pthread_mutex_lock returned " + printable::formatString(code) + ")");
440 }
441}
442
443inline bool original::pMutex::tryLock() {
444 if (const int code = pthread_mutex_trylock(&this->mutex_);
445 code != 0) {
446 if (code == EBUSY)
447 return false;
448
449 throw sysError("Failed to try-lock mutex (pthread_mutex_try-lock returned " + printable::formatString(code) + ")");
450 }
451 return true;
452}
453
454inline void original::pMutex::unlock() {
455 if (const int code = pthread_mutex_unlock(&this->mutex_);
456 code != 0){
457 throw sysError("Failed to unlock mutex (pthread_mutex_unlock returned " + printable::formatString(code) + ")");
458 }
459}
460
461inline original::pMutex::~pMutex() {
462 if (const int code = pthread_mutex_destroy(&this->mutex_);
463 code != 0){
464 std::cerr << "Fatal error: Failed to destroy mutex (pthread_mutex_destroy returned "
465 << code << ")" << std::endl;
466 std::terminate();
467 }
468}
469#elif ORIGINAL_COMPILER_MSVC
470inline original::wMutex::wMutex()
471{
472 InitializeSRWLock(&this->lock_);
473}
474
475inline original::ul_integer original::wMutex::id() const
476{
477 return reinterpret_cast<ul_integer>(&this->lock_);
478}
479
480inline void* original::wMutex::nativeHandle() noexcept
481{
482 return &this->lock_;
483}
484
485inline void original::wMutex::lock()
486{
487 AcquireSRWLockExclusive(&this->lock_);
488}
489
490inline bool original::wMutex::tryLock()
491{
492 return TryAcquireSRWLockExclusive(&this->lock_) != 0;
493}
494
495inline void original::wMutex::unlock()
496{
497 ReleaseSRWLockExclusive(&this->lock_);
498}
499
500inline original::wMutex::~wMutex() = default;
501
502#endif
503
504inline original::mutex::mutex() = default;
505
507{
508 return this->mutex_.id();
509}
510
512{
513 return this->mutex_.nativeHandle();
514}
515
517{
518 this->mutex_.lock();
519}
520
522{
523 return this->mutex_.tryLock();
524}
525
527{
528 this->mutex_.unlock();
529}
530
532 : mutex_(mutex), is_locked(false) {
533 switch (policy) {
534 case MANUAL_LOCK:
535 break;
536 case AUTO_LOCK:
537 this->lock();
538 break;
539 case TRY_LOCK:
540 this->tryLock();
541 break;
542 case ADOPT_LOCK:
543 this->is_locked = true;
544 }
545}
546
548 return this->is_locked;
549}
550
552 if (this->is_locked)
553 throw sysError("Cannot lock uniqueLock: already locked");
554
555 this->mutex_.lock();
556 this->is_locked = true;
557}
558
560 if (this->is_locked)
561 throw sysError("Cannot try-lock uniqueLock: already locked");
562
563 this->is_locked = this->mutex_.tryLock();
564 return this->is_locked;
565}
566
568 if (this->is_locked){
569 this->mutex_.unlock();
570 this->is_locked = false;
571 }
572}
573
575 this->unlock();
576}
577
578template<typename... MUTEX>
579template<original::u_integer... IDXES>
581 (..., this->m_list.template get<IDXES>()->lock());
582 this->is_locked_all = true;
583}
584
585template<typename... MUTEX>
586template<original::u_integer... IDXES>
587bool original::multiLock<MUTEX...>::tryLockAll(indexSequence<IDXES...>) {
588 bool success = true;
589 bool lock_status[sizeof...(IDXES)] = {};
590 auto tryLockStatusUpdate = [&](auto i, auto* mutex) {
591 if (mutex->tryLock()) {
592 lock_status[i] = true;
593 } else {
594 success = false;
595 }
596 };
597
598 u_integer idx = 0;
599 ((tryLockStatusUpdate(idx++, this->m_list.template get<IDXES>())), ...);
600
601 if (!success) {
602 idx = 0;
603 ((lock_status[idx]
604 ? this->m_list.template get<IDXES>()->unlock() : void(), ++idx), ...);
605 }
606 this->is_locked_all = success;
607 return success;
608}
609
610template<typename... MUTEX>
611template<original::u_integer... IDXES>
612void original::multiLock<MUTEX...>::unlockAll(indexSequence<IDXES...>) {
613 (..., this->m_list.template get<IDXES>()->unlock());
614}
615
616template<typename... MUTEX>
619
620template<typename... MUTEX>
622 : m_list(&mutex...), is_locked_all(false) {
623 switch (policy) {
624 case MANUAL_LOCK:
625 break;
626 case AUTO_LOCK:
627 this->lock();
628 break;
629 case TRY_LOCK:
630 this->tryLock();
631 break;
632 case ADOPT_LOCK:
633 this->is_locked_all = true;
634 }
635}
636
637template<typename... MUTEX>
639 return this->is_locked_all;
640}
641
642template<typename... MUTEX>
644 if (this->is_locked_all)
645 throw sysError("Cannot lock multiLock: already locked");
646
647 this->lockAll(makeSequence<sizeof...(MUTEX)>());
648}
649
650template<typename... MUTEX>
652 if (this->is_locked_all)
653 throw sysError("Cannot try-lock multiLock: already locked");
654
655 return this->tryLockAll(makeSequence<sizeof...(MUTEX)>());
656}
657
658template<typename... MUTEX>
660 if (this->is_locked_all)
661 this->unlockAll(makeReverseSequence<sizeof...(MUTEX)>());
662}
663
664template<typename... MUTEX>
668
669#endif //MUTEX_H
Abstract base class for lock guard implementations.
Definition mutex.h:91
static constexpr auto TRY_LOCK
Constant for try-lock policy.
Definition mutex.h:134
static constexpr auto AUTO_LOCK
Constant for automatic lock policy.
Definition mutex.h:132
lockPolicy
Locking policies for guard construction.
Definition mutex.h:122
lockGuard & operator=(const lockGuard &)=delete
Deleted copy assignment operator.
virtual bool tryLock()=0
Attempts to lock the associated mutex(es) without blocking.
virtual void unlock()=0
Unlocks the associated mutex(es)
virtual bool isLocked() const noexcept=0
Checks if the guard currently holds the lock.
lockGuard()=default
Default constructor.
static constexpr auto MANUAL_LOCK
Constant for manual lock policy.
Definition mutex.h:130
virtual void lock()=0
Locks the associated mutex(es)
virtual ~lockGuard()=default
Virtual destructor.
lockGuard(const lockGuard &)=delete
Deleted copy constructor.
static constexpr auto ADOPT_LOCK
Constant for adopt lock policy.
Definition mutex.h:136
RAII wrapper for multiple mutex locking.
Definition mutex.h:339
void unlock() override
Unlocks all managed mutexes.
Definition mutex.h:659
multiLock & operator=(multiLock &&)=delete
Deleted move assignment operator.
void lock() override
Locks all managed mutexes.
Definition mutex.h:643
bool tryLock() override
Attempts to lock all managed mutexes without blocking.
Definition mutex.h:651
multiLock(multiLock &&)=delete
Deleted move constructor.
multiLock(MUTEX &... mutex)
Constructs a multiLock with AUTO_LOCK policy.
Definition mutex.h:617
bool isLocked() const noexcept override
Checks if all mutexes are currently locked.
Definition mutex.h:638
~multiLock() override
Destructor - automatically unlocks all if locked.
Definition mutex.h:665
Abstract base class for mutex implementations.
Definition mutex.h:37
virtual void unlock()=0
Unlocks the mutex.
virtual void * nativeHandle() noexcept=0
Gets the native handle of the mutex.
mutexBase(const mutexBase &)=delete
Deleted copy constructor.
mutexBase & operator=(const mutexBase &)=delete
Deleted copy assignment operator.
virtual void lock()=0
Locks the mutex, blocking if necessary.
virtual bool tryLock()=0
Attempts to lock the mutex without blocking.
virtual ul_integer id() const =0
Gets a unique identifier for the mutex.
mutexBase()=default
Default constructor.
Definition mutex.h:241
bool tryLock() override
Attempts to lock the mutex without blocking.
Definition mutex.h:521
ul_integer id() const override
Gets a unique identifier for the mutex.
Definition mutex.h:506
void unlock() override
Unlocks the mutex.
Definition mutex.h:526
void lock() override
Locks the mutex, blocking if necessary.
Definition mutex.h:516
void * nativeHandle() noexcept override
Gets the native handle of the mutex.
Definition mutex.h:511
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
TYPE * unlock()
Release ownership of managed object.
Definition ownerPtr.h:218
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
Container for multiple heterogeneous elements.
Definition tuple.h:57
RAII wrapper for single mutex locking.
Definition mutex.h:280
void unlock() override
Unlocks the associated mutex.
Definition mutex.h:567
uniqueLock & operator=(uniqueLock &&)=delete
Deleted move assignment operator.
void lock() override
Locks the associated mutex.
Definition mutex.h:551
uniqueLock(uniqueLock &&)=delete
Deleted move constructor.
bool isLocked() const noexcept override
Checks if the lock is currently held.
Definition mutex.h:547
uniqueLock(mutexBase &mutex, lockPolicy policy=AUTO_LOCK)
Constructs a uniqueLock with specified policy.
Definition mutex.h:531
bool tryLock() override
Attempts to lock the associated mutex without blocking.
Definition mutex.h:559
~uniqueLock() override
Destructor - automatically unlocks if locked.
Definition mutex.h:574
Platform-independent type definitions and compiler/platform detection.
Custom exception classes and callback validation utilities.
Main namespace for the project Original.
Definition algorithms.h:21
consteval auto makeSequence() noexcept
Creates an index sequence of given length.
Definition types.h:679
Heterogeneous tuple container implementation.
Time and date handling utilities.