CppCommon  1.0.4.1
C++ Common Library
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 
27 namespace CppCommon {
28 
30 
31 class Mutex::Impl
32 {
33 public:
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 
140 private:
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 
167 bool Mutex::TryLock() { return impl().TryLock(); }
168 bool Mutex::TryLockFor(const Timespan& timespan) { return impl().TryLockFor(timespan); }
169 
170 void Mutex::Lock() { impl().Lock(); }
171 void 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
static void Yield() noexcept
Yield to other threads.
Definition: thread.cpp:143
#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.
Definition: token_bucket.h:15
Thread definition.
Aligned storage validator definition.