CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
mutex.cpp
Go to the documentation of this file.
1
9#include "threads/mutex.h"
10
11#include "errors/fatal.h"
13
14#include <algorithm>
15
16#if defined(__APPLE__) || defined(__CYGWIN__)
17#include "threads/thread.h"
18#endif
19#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
20#include <pthread.h>
21#elif defined(_WIN32) || defined(_WIN64)
22#include <windows.h>
23#undef max
24#undef min
25#endif
26
27namespace CppCommon {
28
30
31class Mutex::Impl
32{
33public:
34 Impl()
35 {
36#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
37 int result = pthread_mutex_init(&_mutex, nullptr);
38 if (result != 0)
39 throwex SystemException("Failed to initialize a mutex!", result);
40#elif defined(_WIN32) || defined(_WIN64)
41 _mutex = CreateMutex(nullptr, FALSE, nullptr);
42 if (_mutex == nullptr)
43 throwex SystemException("Failed to create a mutex!");
44#endif
45 }
46
47 ~Impl()
48 {
49#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
50 int result = pthread_mutex_destroy(&_mutex);
51 if (result != 0)
52 fatality(SystemException("Failed to destroy a mutex!", result));
53#elif defined(_WIN32) || defined(_WIN64)
54 if (!CloseHandle(_mutex))
55 fatality(SystemException("Failed to close a mutex!"));
56#endif
57 }
58
59 bool TryLock()
60 {
61#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
62 int result = pthread_mutex_trylock(&_mutex);
63 if ((result != 0) && (result != EAGAIN) && (result != EBUSY) && (result != EDEADLK))
64 throwex SystemException("Failed to try lock a mutex!", result);
65 return (result == 0);
66#elif defined(_WIN32) || defined(_WIN64)
67 DWORD result = WaitForSingleObject(_mutex, 0);
68 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
69 throwex SystemException("Failed to try lock a mutex!");
70 return (result == WAIT_OBJECT_0);
71#endif
72 }
73
74 bool TryLockFor(const Timespan& timespan)
75 {
76 if (timespan < 0)
77 return TryLock();
78#if defined(__APPLE__) || defined(__CYGWIN__)
79 // Calculate a finish timestamp
80 Timestamp finish = NanoTimestamp() + timespan;
81
82 // Try to acquire lock at least one time
83 if (TryLock())
84 return true;
85 else
86 {
87 // Try lock or yield for the given timespan
88 while (NanoTimestamp() < finish)
89 {
90 if (TryLock())
91 return true;
92 else
93 Thread::Yield();
94 }
95
96 // Failed to acquire lock
97 return false;
98 }
99#elif defined(unix) || defined(__unix) || defined(__unix__)
100 struct timespec timeout;
101 timeout.tv_sec = timespan.seconds();
102 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
103 int result = pthread_mutex_timedlock(&_mutex, &timeout);
104 if ((result != 0) && (result != ETIMEDOUT))
105 throwex SystemException("Failed to try lock a mutex for the given timeout!", result);
106 return (result == 0);
107#elif defined(_WIN32) || defined(_WIN64)
108 DWORD result = WaitForSingleObject(_mutex, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
109 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
110 throwex SystemException("Failed to try lock a mutex for the given timeout!");
111 return (result == WAIT_OBJECT_0);
112#endif
113 }
114
115 void Lock()
116 {
117#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
118 int result = pthread_mutex_lock(&_mutex);
119 if (result != 0)
120 throwex SystemException("Failed to lock a mutex!", result);
121#elif defined(_WIN32) || defined(_WIN64)
122 DWORD result = WaitForSingleObject(_mutex, INFINITE);
123 if (result != WAIT_OBJECT_0)
124 throwex SystemException("Failed to lock a mutex!");
125#endif
126 }
127
128 void Unlock()
129 {
130#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
131 int result = pthread_mutex_unlock(&_mutex);
132 if (result != 0)
133 throwex SystemException("Failed to unlock a mutex!", result);
134#elif defined(_WIN32) || defined(_WIN64)
135 if (!ReleaseMutex(_mutex))
136 throwex SystemException("Failed to unlock a mutex!");
137#endif
138 }
139
140private:
141#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
142 pthread_mutex_t _mutex;
143#elif defined(_WIN32) || defined(_WIN64)
144 HANDLE _mutex;
145#endif
146};
147
149
151{
152 // Check implementation storage parameters
153 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
154 static_assert((StorageSize >= sizeof(Impl)), "Mutex::StorageSize must be increased!");
155 static_assert(((StorageAlign % alignof(Impl)) == 0), "Mutex::StorageAlign must be adjusted!");
156
157 // Create the implementation instance
158 new(&_storage)Impl();
159}
160
162{
163 // Delete the implementation instance
164 reinterpret_cast<Impl*>(&_storage)->~Impl();
165}
166
167bool Mutex::TryLock() { return impl().TryLock(); }
168bool Mutex::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
169
170void Mutex::Lock() { impl().Lock(); }
171void Mutex::Unlock() { impl().Unlock(); }
172
173} // namespace CppCommon
bool TryLock()
Try to acquire mutex without block.
Definition mutex.cpp:167
void Lock()
Acquire mutex with block.
Definition mutex.cpp:170
void Unlock()
Release mutex.
Definition mutex.cpp:171
bool TryLockFor(const Timespan &timespan)
Try to acquire mutex for the given timespan.
Definition mutex.cpp:168
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition fatal.h:22
Mutex synchronization primitive definition.
C++ Common project definitions.
Thread definition.
Aligned storage validator definition.