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 "pthread.h"
5#include "error.h"
6#include "tuple.h"
7#include <iostream>
8
18namespace original {
30 class mutexBase {
31 protected:
36 virtual void lock() = 0;
37
43 virtual bool tryLock() = 0;
44
49 virtual void unlock() = 0;
50
55 [[nodiscard]] virtual ul_integer id() const = 0;
56
57 public:
59 explicit mutexBase() = default;
60
62 mutexBase(const mutexBase&) = delete;
63
65 mutexBase& operator=(const mutexBase&) = delete;
66
71 [[nodiscard]] virtual void* nativeHandle() noexcept = 0;
72
74 virtual ~mutexBase() = default;
75 };
76
85 class lockGuard {
86 protected:
91 virtual void lock() = 0;
92
98 virtual bool tryLock() = 0;
99
104 virtual void unlock() = 0;
105
110 [[nodiscard]] virtual bool isLocked() const noexcept = 0;
111 public:
116 enum class lockPolicy {
117 MANUAL_LOCK,
118 AUTO_LOCK,
119 TRY_LOCK,
120 ADOPT_LOCK,
121 };
122
124 static constexpr auto MANUAL_LOCK = lockPolicy::MANUAL_LOCK;
126 static constexpr auto AUTO_LOCK = lockPolicy::AUTO_LOCK;
128 static constexpr auto TRY_LOCK = lockPolicy::TRY_LOCK;
130 static constexpr auto ADOPT_LOCK = lockPolicy::ADOPT_LOCK;
131
133 explicit lockGuard() = default;
134
136 lockGuard(const lockGuard&) = delete;
137
139 lockGuard& operator=(const lockGuard&) = delete;
140
142 virtual ~lockGuard() = default;
143 };
144
153 class pMutex final : public mutexBase {
154 pthread_mutex_t mutex_;
155 public:
157 using native_handle = pthread_mutex_t;
158
163 explicit pMutex();
164
166 pMutex(pMutex&&) = delete;
167
169 pMutex& operator=(pMutex&&) = delete;
170
175 [[nodiscard]] ul_integer id() const override;
176
181 [[nodiscard]] void* nativeHandle() noexcept override;
182
187 void lock() override;
188
194 bool tryLock() override;
195
200 void unlock() override;
201
206 ~pMutex() override;
207 };
208
216 class uniqueLock final : public lockGuard {
217 pMutex& p_mutex_;
218 bool is_locked;
219
220 public:
227 explicit uniqueLock(pMutex& p_mutex, lockPolicy policy = AUTO_LOCK);
228
231
234
239 [[nodiscard]] bool isLocked() const noexcept override;
240
245 void lock() override;
246
252 bool tryLock() override;
253
258 void unlock() override;
259
263 ~uniqueLock() override;
264 };
265
274 template<typename... MUTEX>
275 class multiLock final : public lockGuard {
276 tuple<MUTEX* ...> m_list;
277 bool is_locked_all;
278
284 template<u_integer... IDXES>
285 void lockAll(indexSequence<IDXES...> sequence);
286
293 template<u_integer... IDXES>
294 bool tryLockAll(indexSequence<IDXES...> sequence);
295
301 template<u_integer... IDXES>
302 void unlockAll(indexSequence<IDXES...> sequence);
303 public:
308 explicit multiLock(MUTEX&... mutex);
309
315 explicit multiLock(lockPolicy policy, MUTEX&... mutex);
316
321 [[nodiscard]] bool isLocked() const noexcept override;
322
327 void lock() override;
328
334 bool tryLock() override;
335
340 void unlock() override;
341
343 multiLock(multiLock&&) = delete;
344
347
351 ~multiLock() override;
352 };
353}
354
355inline original::pMutex::pMutex() : mutex_{} {
356 if (const int code = pthread_mutex_init(&this->mutex_, nullptr);
357 code != 0){
358 throw sysError("Failed to initialize mutex (pthread_mutex_init returned " + printable::formatString(code) + ")");
359 }
360}
361
363 return reinterpret_cast<ul_integer>(&this->mutex_);
364}
365
366inline void* original::pMutex::nativeHandle() noexcept
367{
368 return &this->mutex_;
369}
370
372 if (const int code = pthread_mutex_lock(&this->mutex_);
373 code != 0) {
374 throw sysError("Failed to lock mutex (pthread_mutex_lock returned " + printable::formatString(code) + ")");
375 }
376}
377
379 if (const int code = pthread_mutex_trylock(&this->mutex_);
380 code != 0) {
381 if (code == EBUSY)
382 return false;
383
384 throw sysError("Failed to try-lock mutex (pthread_mutex_try-lock returned " + printable::formatString(code) + ")");
385 }
386 return true;
387}
388
390 if (const int code = pthread_mutex_unlock(&this->mutex_);
391 code != 0){
392 throw sysError("Failed to unlock mutex (pthread_mutex_unlock returned " + printable::formatString(code) + ")");
393 }
394}
395
397 if (const int code = pthread_mutex_destroy(&this->mutex_);
398 code != 0){
399 std::cerr << "Fatal error: Failed to destroy mutex (pthread_mutex_destroy returned "
400 << code << ")" << std::endl;
401 std::terminate();
402 }
403}
404
406 : p_mutex_(p_mutex), is_locked(false) {
407 switch (policy) {
408 case MANUAL_LOCK:
409 break;
410 case AUTO_LOCK:
411 this->lock();
412 break;
413 case TRY_LOCK:
414 this->tryLock();
415 break;
416 case ADOPT_LOCK:
417 this->is_locked = true;
418 }
419}
420
421inline bool original::uniqueLock::isLocked() const noexcept {
422 return this->is_locked;
423}
424
426 if (this->is_locked)
427 throw sysError("Cannot lock uniqueLock: already locked");
428
429 this->p_mutex_.lock();
430 this->is_locked = true;
431}
432
434 if (this->is_locked)
435 throw sysError("Cannot try-lock uniqueLock: already locked");
436
437 this->is_locked = this->p_mutex_.tryLock();
438 return this->is_locked;
439}
440
442 if (this->is_locked){
443 this->p_mutex_.unlock();
444 this->is_locked = false;
445 }
446}
447
449 this->unlock();
450}
451
452template<typename... MUTEX>
453template<original::u_integer... IDXES>
455 (..., this->m_list.template get<IDXES>()->lock());
456 this->is_locked_all = true;
457}
458
459template<typename... MUTEX>
460template<original::u_integer... IDXES>
461bool original::multiLock<MUTEX...>::tryLockAll(indexSequence<IDXES...>) {
462 bool success = true;
463 bool lock_status[sizeof...(IDXES)] = {};
464 auto tryLockStatusUpdate = [&](auto i, auto* mutex) {
465 if (mutex->tryLock()) {
466 lock_status[i] = true;
467 } else {
468 success = false;
469 }
470 };
471
472 u_integer idx = 0;
473 ((tryLockStatusUpdate(idx++, this->m_list.template get<IDXES>())), ...);
474
475 if (!success) {
476 idx = 0;
477 ((lock_status[idx]
478 ? this->m_list.template get<IDXES>()->unlock() : void(), ++idx), ...);
479 }
480 this->is_locked_all = success;
481 return success;
482}
483
484template<typename... MUTEX>
485template<original::u_integer... IDXES>
486void original::multiLock<MUTEX...>::unlockAll(indexSequence<IDXES...>) {
487 (..., this->m_list.template get<IDXES>()->unlock());
488}
489
490template<typename... MUTEX>
492 : multiLock(AUTO_LOCK, mutex...) {}
493
494template<typename... MUTEX>
496 : m_list(&mutex...), is_locked_all(false) {
497 switch (policy) {
498 case MANUAL_LOCK:
499 break;
500 case AUTO_LOCK:
501 this->lock();
502 break;
503 case TRY_LOCK:
504 this->tryLock();
505 break;
506 case ADOPT_LOCK:
507 this->is_locked_all = true;
508 }
509}
510
511template<typename... MUTEX>
513 return this->is_locked_all;
514}
515
516template<typename... MUTEX>
518 if (this->is_locked_all)
519 throw sysError("Cannot lock multiLock: already locked");
520
521 this->lockAll(makeSequence<sizeof...(MUTEX)>());
522}
523
524template<typename... MUTEX>
526 if (this->is_locked_all)
527 throw sysError("Cannot try-lock multiLock: already locked");
528
529 return this->tryLockAll(makeSequence<sizeof...(MUTEX)>());
530}
531
532template<typename... MUTEX>
534 if (this->is_locked_all)
535 this->unlockAll(makeReverseSequence<sizeof...(MUTEX)>());
536}
537
538template<typename... MUTEX>
542
543#endif //MUTEX_H
Compile-time sequence of unsigned integers.
Definition types.h:255
Abstract base class for lock guard implementations.
Definition mutex.h:85
static constexpr auto TRY_LOCK
Constant for try-lock policy.
Definition mutex.h:128
static constexpr auto AUTO_LOCK
Constant for automatic lock policy.
Definition mutex.h:126
lockPolicy
Locking policies for guard construction.
Definition mutex.h:116
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:124
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:130
RAII wrapper for multiple mutex locking.
Definition mutex.h:275
void unlock() override
Unlocks all managed mutexes.
Definition mutex.h:533
multiLock & operator=(multiLock &&)=delete
Deleted move assignment operator.
void lock() override
Locks all managed mutexes.
Definition mutex.h:517
bool tryLock() override
Attempts to lock all managed mutexes without blocking.
Definition mutex.h:525
multiLock(multiLock &&)=delete
Deleted move constructor.
multiLock(MUTEX &... mutex)
Constructs a multiLock with AUTO_LOCK policy.
Definition mutex.h:491
bool isLocked() const noexcept override
Checks if all mutexes are currently locked.
Definition mutex.h:512
~multiLock() override
Destructor - automatically unlocks all if locked.
Definition mutex.h:539
Abstract base class for mutex implementations.
Definition mutex.h:30
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.
POSIX thread mutex implementation.
Definition mutex.h:153
pMutex(pMutex &&)=delete
Deleted move constructor.
void unlock() override
Unlocks the mutex.
Definition mutex.h:389
pthread_mutex_t native_handle
Native handle type (pthread_mutex_t)
Definition mutex.h:157
pMutex()
Constructs and initializes the mutex.
Definition mutex.h:355
bool tryLock() override
Attempts to lock the mutex without blocking.
Definition mutex.h:378
ul_integer id() const override
Gets a unique identifier for the mutex.
Definition mutex.h:362
pMutex & operator=(pMutex &&)=delete
Deleted move assignment operator.
~pMutex() override
Destroys the mutex.
Definition mutex.h:396
void * nativeHandle() noexcept override
Gets the native mutex handle.
Definition mutex.h:366
void lock() override
Locks the mutex, blocking if necessary.
Definition mutex.h:371
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
Container for multiple heterogeneous elements.
Definition tuple.h:53
RAII wrapper for single mutex locking.
Definition mutex.h:216
void unlock() override
Unlocks the associated mutex.
Definition mutex.h:441
uniqueLock & operator=(uniqueLock &&)=delete
Deleted move assignment operator.
void lock() override
Locks the associated mutex.
Definition mutex.h:425
uniqueLock(uniqueLock &&)=delete
Deleted move constructor.
uniqueLock(pMutex &p_mutex, lockPolicy policy=AUTO_LOCK)
Constructs a uniqueLock with specified policy.
Definition mutex.h:405
bool isLocked() const noexcept override
Checks if the lock is currently held.
Definition mutex.h:421
bool tryLock() override
Attempts to lock the associated mutex without blocking.
Definition mutex.h:433
~uniqueLock() override
Destructor - automatically unlocks if locked.
Definition mutex.h:448
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
Main namespace for the project Original.
Definition algorithms.h:21
consteval auto makeSequence() noexcept
Creates an index sequence of given length.
Definition types.h:386
decltype( reverseIndexSequenceImpl(makeSequence< N >())) makeReverseSequence
Creates a reversed index sequence.
Definition types.h:313
Heterogeneous tuple container implementation.