CppCommon  1.0.4.1
C++ Common Library
rw_lock.cpp
Go to the documentation of this file.
1 
9 #include "threads/rw_lock.h"
10 
11 #include "threads/thread.h"
13 
14 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
15 #include "errors/fatal.h"
16 #include <pthread.h>
17 #elif defined(_WIN32) || defined(_WIN64)
18 #include <windows.h>
19 #undef Yield
20 #endif
21 
22 namespace CppCommon {
23 
25 
26 class RWLock::Impl
27 {
28 public:
29  Impl()
30  {
31 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
32  int result = pthread_rwlock_init(&_rwlock, nullptr);
33  if (result != 0)
34  throwex SystemException("Failed to initialize a read/write lock!", result);
35 #elif defined(_WIN32) || defined(_WIN64)
36  InitializeSRWLock(&_rwlock);
37 #endif
38  }
39 
40  ~Impl()
41  {
42 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
43  int result = pthread_rwlock_destroy(&_rwlock);
44  if (result != 0)
45  fatality(SystemException("Failed to destroy a read/write lock!", result));
46 #elif defined(_WIN32) || defined(_WIN64)
47  // SRW locks do not need to be explicitly destroyed.
48 #endif
49  }
50 
51  bool TryLockRead()
52  {
53 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
54  int result = pthread_rwlock_tryrdlock(&_rwlock);
55  if ((result != 0) && (result != EAGAIN) && (result != EBUSY) && (result != EDEADLK))
56  throwex SystemException("Failed to try lock for read!", result);
57  return (result == 0);
58 #elif defined(_WIN32) || defined(_WIN64)
59  return (TryAcquireSRWLockShared(&_rwlock) != 0);
60 #endif
61  }
62 
63  bool TryLockWrite()
64  {
65 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
66  int result = pthread_rwlock_trywrlock(&_rwlock);
67  if ((result != 0) && (result != EAGAIN) && (result != EBUSY) && (result != EDEADLK))
68  throwex SystemException("Failed to try lock for write!", result);
69  return (result == 0);
70 #elif defined(_WIN32) || defined(_WIN64)
71  return (TryAcquireSRWLockExclusive(&_rwlock) != 0);
72 #endif
73  }
74 
75  void LockRead()
76  {
77 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
78  int result = pthread_rwlock_rdlock(&_rwlock);
79  if (result != 0)
80  throwex SystemException("Failed to lock for read!", result);
81 #elif defined(_WIN32) || defined(_WIN64)
82  AcquireSRWLockShared(&_rwlock);
83 #endif
84  }
85 
86  void LockWrite()
87  {
88 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
89  int result = pthread_rwlock_wrlock(&_rwlock);
90  if (result != 0)
91  throwex SystemException("Failed to lock for write!", result);
92 #elif defined(_WIN32) || defined(_WIN64)
93  AcquireSRWLockExclusive(&_rwlock);
94 #endif
95  }
96 
97  void UnlockRead()
98  {
99 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
100  int result = pthread_rwlock_unlock(&_rwlock);
101  if (result != 0)
102  throwex SystemException("Failed to unlock read lock!", result);
103 #elif defined(_WIN32) || defined(_WIN64)
104  ReleaseSRWLockShared(&_rwlock);
105 #endif
106  }
107 
108  void UnlockWrite()
109  {
110 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
111  int result = pthread_rwlock_unlock(&_rwlock);
112  if (result != 0)
113  throwex SystemException("Failed to unlock write lock!", result);
114 #elif defined(_WIN32) || defined(_WIN64)
115  ReleaseSRWLockExclusive(&_rwlock);
116 #endif
117  }
118 
119 private:
120 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
121  pthread_rwlock_t _rwlock;
122 #elif defined(_WIN32) || defined(_WIN64)
123  SRWLOCK _rwlock;
124 #endif
125 };
126 
128 
130 {
131  // Check implementation storage parameters
132  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
133  static_assert((StorageSize >= sizeof(Impl)), "RWLock::StorageSize must be increased!");
134  static_assert(((StorageAlign % alignof(Impl)) == 0), "RWLock::StorageAlign must be adjusted!");
135 
136  // Create the implementation instance
137  new(&_storage)Impl();
138 }
139 
141 {
142  // Delete the implementation instance
143  reinterpret_cast<Impl*>(&_storage)->~Impl();
144 }
145 
146 bool RWLock::TryLockRead() { return impl().TryLockRead(); }
147 bool RWLock::TryLockWrite() { return impl().TryLockWrite(); }
148 
149 bool RWLock::TryLockReadFor(const Timespan& timespan)
150 {
151  // Calculate a finish timestamp
152  Timestamp finish = NanoTimestamp() + timespan;
153 
154  // Try to acquire read lock at least one time
155  if (TryLockRead())
156  return true;
157  else
158  {
159  // Try lock or yield for the given timespan
160  while (NanoTimestamp() < finish)
161  {
162  if (TryLockRead())
163  return true;
164  else
165  Thread::Yield();
166  }
167 
168  // Failed to acquire read lock
169  return false;
170  }
171 }
172 
173 bool RWLock::TryLockWriteFor(const Timespan& timespan)
174 {
175  // Calculate a finish timestamp
176  Timestamp finish = NanoTimestamp() + timespan;
177 
178  // Try to acquire write lock at least one time
179  if (TryLockWrite())
180  return true;
181  else
182  {
183  // Try lock or yield for the given timespan
184  while (NanoTimestamp() < finish)
185  {
186  if (TryLockWrite())
187  return true;
188  else
189  Thread::Yield();
190  }
191 
192  // Failed to acquire write lock
193  return false;
194  }
195 }
196 
197 void RWLock::LockRead() { impl().LockRead(); }
198 void RWLock::LockWrite() { impl().LockWrite(); }
199 void RWLock::UnlockRead() { impl().UnlockRead(); }
200 void RWLock::UnlockWrite() { impl().UnlockWrite(); }
201 
202 } // namespace CppCommon
High resolution timestamp.
Definition: timestamp.h:272
void UnlockRead()
Release read lock.
Definition: rw_lock.cpp:199
void LockWrite()
Acquire write lock with block.
Definition: rw_lock.cpp:198
void UnlockWrite()
Release write lock.
Definition: rw_lock.cpp:200
bool TryLockRead()
Try to acquire read lock without block.
Definition: rw_lock.cpp:146
void LockRead()
Acquire read lock with block.
Definition: rw_lock.cpp:197
bool TryLockReadFor(const Timespan &timespan)
Try to acquire read lock for the given timespan.
Definition: rw_lock.cpp:149
bool TryLockWrite()
Try to acquire write lock without block.
Definition: rw_lock.cpp:147
bool TryLockWriteFor(const Timespan &timespan)
Try to acquire write lock for the given timespan.
Definition: rw_lock.cpp:173
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
C++ Common project definitions.
Definition: token_bucket.h:15
Read/Write lock synchronization primitive definition.
Thread definition.
Aligned storage validator definition.