CppCommon  1.0.4.1
C++ Common Library
named_mutex.cpp
Go to the documentation of this file.
1 
9 #include "threads/named_mutex.h"
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 
28 namespace CppCommon {
29 
31 
32 class NamedMutex::Impl
33 {
34 public:
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 
158 private:
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 
176 NamedMutex::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 
193 const std::string& NamedMutex::name() const { return impl().name(); }
194 
195 bool NamedMutex::TryLock() { return impl().TryLock(); }
196 bool NamedMutex::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
197 
198 void NamedMutex::Lock() { impl().Lock(); }
199 void 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.
Definition: token_bucket.h:15
Shared memory type definition.
Thread definition.
Aligned storage validator definition.