CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
named_mutex.cpp
Go to the documentation of this file.
1
10
11#include "errors/fatal.h"
13
14#include <algorithm>
15
16#if defined(__APPLE__)
17#include "threads/thread.h"
18#endif
19#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
20#include "system/shared_type.h"
21#include <pthread.h>
22#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
23#include <windows.h>
24#undef max
25#undef min
26#endif
27
28namespace CppCommon {
29
31
32class NamedMutex::Impl
33{
34public:
35 Impl(const std::string& name) : _name(name)
36#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
37 , _shared(name)
38#endif
39 {
40#if defined(__APPLE__)
41 throwex SystemException("Named mutex is not supported!");
42#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
43 // Only the owner should initializate a named mutex
44 if (_shared.owner())
45 {
46 pthread_mutexattr_t mutex_attribute;
47 int result = pthread_mutexattr_init(&mutex_attribute);
48 if (result != 0)
49 throwex SystemException("Failed to initialize a named mutex attribute!", result);
50 result = pthread_mutexattr_setpshared(&mutex_attribute, PTHREAD_PROCESS_SHARED);
51 if (result != 0)
52 throwex SystemException("Failed to set a named mutex process shared attribute!", result);
53 result = pthread_mutex_init(&_shared->mutex, &mutex_attribute);
54 if (result != 0)
55 throwex SystemException("Failed to initialize a named mutex!", result);
56 result = pthread_mutexattr_destroy(&mutex_attribute);
57 if (result != 0)
58 throwex SystemException("Failed to destroy a named mutex attribute!", result);
59 }
60#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
61 _mutex = CreateMutexA(nullptr, FALSE, name.c_str());
62 if (_mutex == nullptr)
63 throwex SystemException("Failed to create or open a named mutex!");
64#endif
65 }
66
67 ~Impl()
68 {
69#if defined(__APPLE__)
70 fatality(SystemException("Named mutex is not supported!"));
71#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
72 // Only the owner should destroy a named mutex
73 if (_shared.owner())
74 {
75 int result = pthread_mutex_destroy(&_shared->mutex);
76 if (result != 0)
77 fatality(SystemException("Failed to destroy a named mutex!", result));
78 }
79#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
80 if (!CloseHandle(_mutex))
81 fatality(SystemException("Failed to close a named mutex!"));
82#endif
83 }
84
85 const std::string& name() const
86 {
87 return _name;
88 }
89
90 bool TryLock()
91 {
92#if defined(__APPLE__)
93 throwex SystemException("Named mutex is not supported!");
94#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
95 int result = pthread_mutex_trylock(&_shared->mutex);
96 if ((result != 0) && (result != EAGAIN) && (result != EBUSY) && (result != EDEADLK))
97 throwex SystemException("Failed to try lock a named mutex!", result);
98 return (result == 0);
99#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
100 DWORD result = WaitForSingleObject(_mutex, 0);
101 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
102 throwex SystemException("Failed to try lock a named mutex!");
103 return (result == WAIT_OBJECT_0);
104#endif
105 }
106
107 bool TryLockFor(const Timespan& timespan)
108 {
109 if (timespan < 0)
110 return TryLock();
111#if defined(__APPLE__)
112 throwex SystemException("Named mutex is not supported!");
113#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
114 struct timespec timeout;
115 timeout.tv_sec = timespan.seconds();
116 timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
117 int result = pthread_mutex_timedlock(&_shared->mutex, &timeout);
118 if ((result != 0) && (result != ETIMEDOUT))
119 throwex SystemException("Failed to try lock a named mutex for the given timeout!", result);
120 return (result == 0);
121#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
122 DWORD result = WaitForSingleObject(_mutex, std::max((DWORD)1, (DWORD)timespan.milliseconds()));
123 if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
124 throwex SystemException("Failed to try lock a named mutex for the given timeout!");
125 return (result == WAIT_OBJECT_0);
126#endif
127 }
128
129 void Lock()
130 {
131#if defined(__APPLE__)
132 throwex SystemException("Named mutex is not supported!");
133#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
134 int result = pthread_mutex_lock(&_shared->mutex);
135 if (result != 0)
136 throwex SystemException("Failed to lock a named mutex!", result);
137#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
138 DWORD result = WaitForSingleObject(_mutex, INFINITE);
139 if (result != WAIT_OBJECT_0)
140 throwex SystemException("Failed to lock a named mutex!");
141#endif
142 }
143
144 void Unlock()
145 {
146#if defined(__APPLE__)
147 throwex SystemException("Named mutex is not supported!");
148#elif (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__CYGWIN__)
149 int result = pthread_mutex_unlock(&_shared->mutex);
150 if (result != 0)
151 throwex SystemException("Failed to unlock a named mutex!", result);
152#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
153 if (!ReleaseMutex(_mutex))
154 throwex SystemException("Failed to unlock a named mutex!");
155#endif
156 }
157
158private:
159 std::string _name;
160#if (defined(unix) || defined(__unix) || defined(__unix__)) && !defined(__APPLE__) && !defined(__CYGWIN__)
161 // Shared mutex structure
162 struct MutexHeader
163 {
164 pthread_mutex_t mutex;
165 };
166
167 // Shared mutex structure wrapper
168 SharedType<MutexHeader> _shared;
169#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
170 HANDLE _mutex;
171#endif
172};
173
175
176NamedMutex::NamedMutex(const std::string& name)
177{
178 // Check implementation storage parameters
179 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
180 static_assert((StorageSize >= sizeof(Impl)), "NamedMutex::StorageSize must be increased!");
181 static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedMutex::StorageAlign must be adjusted!");
182
183 // Create the implementation instance
184 new(&_storage)Impl(name);
185}
186
188{
189 // Delete the implementation instance
190 reinterpret_cast<Impl*>(&_storage)->~Impl();
191}
192
193const std::string& NamedMutex::name() const { return impl().name(); }
194
195bool NamedMutex::TryLock() { return impl().TryLock(); }
196bool NamedMutex::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
197
198void NamedMutex::Lock() { impl().Lock(); }
199void NamedMutex::Unlock() { impl().Unlock(); }
200
201} // namespace CppCommon
NamedMutex(const std::string &name)
Default class constructor.
bool TryLock()
Try to acquire mutex without block.
void Unlock()
Release mutex.
const std::string & name() const
Get the mutex name.
void Lock()
Acquire mutex with block.
bool TryLockFor(const Timespan &timespan)
Try to acquire mutex for the given timespan.
#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
Named mutex synchronization primitive definition.
C++ Common project definitions.
Shared memory type definition.
Thread definition.
Aligned storage validator definition.