CppCommon  1.0.4.1
C++ Common Library
named_rw_lock.cpp
Go to the documentation of this file.
1 
10 
11 #include "errors/fatal.h"
12 #include "system/shared_type.h"
13 #include "threads/thread.h"
15 
16 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
17 #include <fcntl.h>
18 #include <semaphore.h>
19 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
20 #include <windows.h>
21 #undef Yield
22 #endif
23 
24 namespace CppCommon {
25 
27 
29 
82 class NamedRWLock::Impl
83 {
84  const uint32_t LOCK_OWNED = 0x1;
85  const uint32_t LOCK_EXCLUSIVE_WAKING = 0x2;
86 
87  const uint32_t LOCK_SHARED_OWNERS_SHIFT = 2;
88  const uint32_t LOCK_SHARED_OWNERS_MASK = 0x3ff;
89  const uint32_t LOCK_SHARED_OWNERS_INC = 0x4;
90 
91  const uint32_t LOCK_SHARED_WAITERS_SHIFT = 12;
92  const uint32_t LOCK_SHARED_WAITERS_MASK = 0x3ff;
93  const uint32_t LOCK_SHARED_WAITERS_INC = 0x1000;
94 
95  const uint32_t LOCK_EXCLUSIVE_WAITERS_SHIFT = 22;
96  const uint32_t LOCK_EXCLUSIVE_WAITERS_MASK = 0x3ff;
97  const uint32_t LOCK_EXCLUSIVE_WAITERS_INC = 0x400000;
98 
99  const uint32_t LOCK_EXCLUSIVE_MASK = (LOCK_EXCLUSIVE_WAKING | (LOCK_EXCLUSIVE_WAITERS_MASK << LOCK_EXCLUSIVE_WAITERS_SHIFT));
100 
101 public:
102  Impl(const std::string& name, uint32_t spin) : _value(name), _spin(spin)
103  {
104  // Owner of the read/write lock should initialize its value
105  if (_value.owner())
106  *_value = 0;
107 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
108  if (_value.owner())
109  {
110  _exclusive_wake = sem_open((this->name() + "_exclusive").c_str(), (O_CREAT | O_EXCL), 0666, 0);
111  if (_exclusive_wake == SEM_FAILED)
112  throwex SystemException("Failed to create an exclusive wake semaphore for the named read/write lock!");
113  _shared_wake = sem_open((this->name() + "_shared").c_str(), (O_CREAT | O_EXCL), 0666, 0);
114  if (_shared_wake == SEM_FAILED)
115  throwex SystemException("Failed to create an shared wake semaphore for the named read/write lock!");
116  }
117  else
118  {
119  _exclusive_wake = sem_open((this->name() + "_exclusive").c_str(), O_CREAT, 0666, 0);
120  if (_exclusive_wake == SEM_FAILED)
121  throwex SystemException("Failed to open an exclusive wake semaphore for the named read/write lock!");
122  _shared_wake = sem_open((this->name() + "_shared").c_str(), O_CREAT, 0666, 0);
123  if (_shared_wake == SEM_FAILED)
124  throwex SystemException("Failed to open an shared wake semaphore for the named read/write lock!");
125  }
126 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
127  _exclusive_wake = CreateSemaphoreA(nullptr, 0, MAXLONG, (this->name() + "_exclusive").c_str());
128  if (_exclusive_wake == nullptr)
129  throwex SystemException("Failed to create or open an exclusive wake semaphore for the named read/write lock!");
130  _shared_wake = CreateSemaphoreA(nullptr, 0, MAXLONG, (this->name() + "_shared").c_str());
131  if (_shared_wake == nullptr)
132  throwex SystemException("Failed to create or open a shared wake semaphore for the named read/write lock!");
133 #endif
134  }
135 
136  ~Impl()
137  {
138 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
139  int result = sem_close(_exclusive_wake);
140  if (result != 0)
141  fatality(SystemException("Failed to close an exclusive wake semaphore for the named read/write lock"));
142  result = sem_close(_shared_wake);
143  if (result != 0)
144  fatality(SystemException("Failed to close an shared wake semaphore for the named read/write lock"));
145  // Unlink the named semaphores (owner only)
146  if (_value.owner())
147  {
148  result = sem_unlink((name() + "_exclusive").c_str());
149  if (result != 0)
150  fatality(SystemException("Failed to unlink an exclusive wake semaphore for the named read/write lock!"));
151  result = sem_unlink((name() + "_shared").c_str());
152  if (result != 0)
153  fatality(SystemException("Failed to unlink an shared wake semaphore for the named read/write lock!"));
154  }
155 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
156  if (!CloseHandle(_exclusive_wake))
157  fatality(SystemException("Failed to close an exclusive wake semaphore for the named read/write lock!"));
158  if (!CloseHandle(_shared_wake))
159  fatality(SystemException("Failed to close a shared wake semaphore for the named read/write lock!"));
160 #endif
161  }
162 
163  const std::string& name() const
164  {
165  return _value.name();
166  }
167 
168  bool TryLockRead()
169  {
170  uint32_t value = (uint32_t)*_value;
171 
172  if (value & LOCK_EXCLUSIVE_MASK)
173  return false;
174 
175  if (!(value & LOCK_OWNED))
176  {
177 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
178  return __sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_OWNED + LOCK_SHARED_OWNERS_INC);
179 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
180  return (InterlockedCompareExchange(_value.ptr(), value + LOCK_OWNED + LOCK_SHARED_OWNERS_INC, value) == value);
181 #endif
182  }
183  else if ((value >> LOCK_SHARED_OWNERS_SHIFT) & LOCK_SHARED_OWNERS_MASK)
184  {
185 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
186  return __sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_SHARED_OWNERS_INC);
187 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
188  return (InterlockedCompareExchange(_value.ptr(), value + LOCK_SHARED_OWNERS_INC, value) == value);
189 #endif
190  }
191  else
192  return false;
193  }
194 
195  bool TryLockWrite()
196  {
197  uint32_t value = (uint32_t)*_value;
198 
199  if (value & (LOCK_OWNED | LOCK_EXCLUSIVE_WAKING))
200  return false;
201 
202 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
203  return __sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_OWNED);
204 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
205  return (InterlockedCompareExchange(_value.ptr(), value + LOCK_OWNED, value) == value);
206 #endif
207  }
208 
209  bool TryConvertWriteToRead()
210  {
211  while (true)
212  {
213  uint32_t value = (uint32_t)*_value;
214 
215  // Can't convert if there are other shared owners
216  if (((value >> LOCK_SHARED_OWNERS_SHIFT) & LOCK_SHARED_OWNERS_MASK) != 1)
217  return false;
218 
219 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
220  if (__sync_bool_compare_and_swap(_value.ptr(), value, value - LOCK_SHARED_OWNERS_INC))
221 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
222  if (InterlockedCompareExchange(_value.ptr(), value - LOCK_SHARED_OWNERS_INC, value) == value)
223 #endif
224  return true;
225  }
226  }
227 
228  void LockRead()
229  {
230  uint32_t iteration = 0;
231 
232  while (true)
233  {
234  uint32_t value = (uint32_t)*_value;
235 
236  // Case 1: lock not owned AND no exclusive waiter is waking up AND
237  // there are no shared owners AND there are no exclusive waiters
238  if (!(value & (LOCK_OWNED | (LOCK_SHARED_OWNERS_MASK << LOCK_SHARED_OWNERS_SHIFT) | LOCK_EXCLUSIVE_MASK)))
239  {
240 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
241  if (__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_OWNED + LOCK_SHARED_OWNERS_INC))
242 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
243  if (InterlockedCompareExchange(_value.ptr(), value + LOCK_OWNED + LOCK_SHARED_OWNERS_INC, value) == value)
244 #endif
245  break;
246  }
247  // Case 2: lock is owned AND no exclusive waiter is waking up AND
248  // there are shared owners AND there are no exclusive waiters
249  else if ((value & LOCK_OWNED) && ((value >> LOCK_SHARED_OWNERS_SHIFT) & LOCK_SHARED_OWNERS_MASK) > 0 && !(value & LOCK_EXCLUSIVE_MASK))
250  {
251 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
252  if (__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_SHARED_OWNERS_INC))
253 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
254  if (InterlockedCompareExchange(_value.ptr(), value + LOCK_SHARED_OWNERS_INC, value) == value)
255 #endif
256  break;
257  }
258  // Other cases
259  else if (iteration++ >= _spin)
260  {
261 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
262  if (__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_SHARED_WAITERS_INC))
263 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
264  if (InterlockedCompareExchange(_value.ptr(), value + LOCK_SHARED_WAITERS_INC, value) == value)
265 #endif
266  {
267  // Go to sleep
268 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
269  int result = sem_wait(_shared_wake);
270  if (result != 0)
271  throwex SystemException("Failed to wait for a shared wake semaphore for the named read/write lock!");
272 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
273  DWORD result = WaitForSingleObject(_shared_wake, INFINITE);
274  if (result != WAIT_OBJECT_0)
275  throwex SystemException("Failed to wait for a shared wake semaphore for the named read/write lock!");
276 #endif
277  // Go back and try again
278  continue;
279  }
280  }
281 
282  // Yield to other threads
283  Thread::Yield();
284  }
285  }
286 
287  void LockWrite()
288  {
289  uint32_t iteration = 0;
290 
291  while (true)
292  {
293  uint32_t value = (uint32_t)*_value;
294 
295  // Case 1: lock not owned AND an exclusive waiter is not waking up.
296  // Here we don't have to check if there are exclusive waiters, because
297  // if there are the lock would be owned, and we are checking that anyway.
298  if (!(value & (LOCK_OWNED | LOCK_EXCLUSIVE_WAKING)))
299  {
300 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
301  if (__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_OWNED))
302 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
303  if (InterlockedCompareExchange(_value.ptr(), value + LOCK_OWNED, value) == value)
304 #endif
305  break;
306  }
307  // Case 2: lock owned OR lock not owned and an exclusive waiter is waking up.
308  // The second case means an exclusive waiter has just been woken up and is
309  // going to acquire the lock. We have to go to sleep to make sure we don't
310  // steal the lock.
311  else if (iteration++ >= _spin)
312  {
313 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
314  if (__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_EXCLUSIVE_WAITERS_INC))
315 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
316  if (InterlockedCompareExchange(_value.ptr(), value + LOCK_EXCLUSIVE_WAITERS_INC, value) == value)
317 #endif
318  {
319 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
320  int result = sem_wait(_exclusive_wake);
321  if (result != 0)
322  throwex SystemException("Failed to wait for an exclusive wake semaphore for the named read/write lock!");
323 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
324  DWORD result = WaitForSingleObject(_exclusive_wake, INFINITE);
325  if (result != WAIT_OBJECT_0)
326  throwex SystemException("Failed to wait for an exclusive wake semaphore for the named read/write lock!");
327 #endif
328  // Acquire the lock.
329  // At this point *no one* should be able to steal the lock from us.
330  do
331  {
332  value = (uint32_t)*_value;
333 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
334  } while (!__sync_bool_compare_and_swap(_value.ptr(), value, value + LOCK_OWNED - LOCK_EXCLUSIVE_WAKING));
335 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
336  } while (InterlockedCompareExchange(_value.ptr(), value + LOCK_OWNED - LOCK_EXCLUSIVE_WAKING, value) != value);
337 #endif
338  break;
339  }
340  }
341 
342  // Yield to other threads
343  Thread::Yield();
344  }
345  }
346 
347  void UnlockRead()
348  {
349  while (true)
350  {
351  uint32_t value = (uint32_t)*_value;
352 
353  // Case 1: there are multiple shared owners
354  if (((value >> LOCK_SHARED_OWNERS_SHIFT) & LOCK_SHARED_OWNERS_MASK) > 1)
355  {
356 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
357  if (__sync_bool_compare_and_swap(_value.ptr(), value, value - LOCK_SHARED_OWNERS_INC))
358 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
359  if (InterlockedCompareExchange(_value.ptr(), value - LOCK_SHARED_OWNERS_INC, value) == value)
360 #endif
361  break;
362  }
363  // Case 2: we are the last shared owner AND there are exclusive waiters
364  else if ((value >> LOCK_EXCLUSIVE_WAITERS_SHIFT) & LOCK_EXCLUSIVE_WAITERS_MASK)
365  {
366 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
367  if (__sync_bool_compare_and_swap(_value.ptr(), value, value - LOCK_OWNED + LOCK_EXCLUSIVE_WAKING - LOCK_SHARED_OWNERS_INC - LOCK_EXCLUSIVE_WAITERS_INC))
368 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
369  if (InterlockedCompareExchange(_value.ptr(), value - LOCK_OWNED + LOCK_EXCLUSIVE_WAKING - LOCK_SHARED_OWNERS_INC - LOCK_EXCLUSIVE_WAITERS_INC, value) == value)
370 #endif
371  {
372 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
373  int result = sem_post(_exclusive_wake);
374  if (result != 0)
375  throwex SystemException("Failed to release an exclusive wake semaphore for the named read/write lock!");
376 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
377  if (!ReleaseSemaphore(_exclusive_wake, 1, nullptr))
378  throwex SystemException("Failed to release an exclusive wake semaphore for the named read/write lock!");
379 #endif
380  break;
381  }
382  }
383  // Case 3: we are the last shared owner AND there are no exclusive waiters
384  else
385  {
386 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
387  if (__sync_bool_compare_and_swap(_value.ptr(), value, value - LOCK_OWNED - LOCK_SHARED_OWNERS_INC))
388 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
389  if (InterlockedCompareExchange(_value.ptr(), value - LOCK_OWNED - LOCK_SHARED_OWNERS_INC, value) == value)
390 #endif
391  break;
392  }
393 
394  // Yield to other threads
395  Thread::Yield();
396  }
397  }
398 
399  void UnlockWrite()
400  {
401  while (true)
402  {
403  uint32_t value = (uint32_t)*_value;
404 
405  // Case 1: if we have exclusive waiters, release one
406  if ((value >> LOCK_EXCLUSIVE_WAITERS_SHIFT) & LOCK_EXCLUSIVE_WAITERS_MASK)
407  {
408 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
409  if (__sync_bool_compare_and_swap(_value.ptr(), value, value - LOCK_OWNED + LOCK_EXCLUSIVE_WAKING - LOCK_EXCLUSIVE_WAITERS_INC))
410 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
411  if (InterlockedCompareExchange(_value.ptr(), value - LOCK_OWNED + LOCK_EXCLUSIVE_WAKING - LOCK_EXCLUSIVE_WAITERS_INC, value) == value)
412 #endif
413  {
414 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
415  int result = sem_post(_exclusive_wake);
416  if (result != 0)
417  throwex SystemException("Failed to release an exclusive wake semaphore for the named read/write lock!");
418 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
419  if (!ReleaseSemaphore(_exclusive_wake, 1, nullptr))
420  throwex SystemException("Failed to release an exclusive wake semaphore for the named read/write lock!");
421 #endif
422  break;
423  }
424  }
425  // Case 2: if we have shared waiters, release all of them
426  else
427  {
428  uint32_t shared_waiters = (value >> LOCK_SHARED_WAITERS_SHIFT) & LOCK_SHARED_WAITERS_MASK;
429 
430 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
431  if (__sync_bool_compare_and_swap(_value.ptr(), value, value & ~(LOCK_OWNED | (LOCK_SHARED_WAITERS_MASK << LOCK_SHARED_WAITERS_SHIFT))))
432 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
433  if (InterlockedCompareExchange(_value.ptr(), value & ~(LOCK_OWNED | (LOCK_SHARED_WAITERS_MASK << LOCK_SHARED_WAITERS_SHIFT)), value) == value)
434 #endif
435  {
436  if (shared_waiters > 0)
437  {
438 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
439  while (shared_waiters-- > 0)
440  {
441  int result = sem_post(_shared_wake);
442  if (result != 0)
443  throwex SystemException("Failed to release a shared wake semaphore for the named read/write lock!");
444  }
445 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
446  if (!ReleaseSemaphore(_shared_wake, shared_waiters, nullptr))
447  throwex SystemException("Failed to release a shared wake semaphore for the named read/write lock!");
448 #endif
449  }
450  break;
451  }
452  }
453 
454  // Yield to other threads
455  Thread::Yield();
456  }
457  }
458 
459  void ConvertWriteToRead()
460  {
461  while (true)
462  {
463  uint32_t value = (uint32_t)*_value;
464 
465  uint32_t shared_waiters = (value >> LOCK_SHARED_WAITERS_SHIFT) & LOCK_SHARED_WAITERS_MASK;
466 
467 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
468  if (__sync_bool_compare_and_swap(_value.ptr(), value, (value + LOCK_SHARED_OWNERS_INC) & ~(LOCK_SHARED_WAITERS_MASK << LOCK_SHARED_WAITERS_SHIFT)))
469 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
470  if (InterlockedCompareExchange(_value.ptr(), (value + LOCK_SHARED_OWNERS_INC) & ~(LOCK_SHARED_WAITERS_MASK << LOCK_SHARED_WAITERS_SHIFT), value) == value)
471 #endif
472  {
473  if (shared_waiters > 0)
474  {
475 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
476  while (shared_waiters-- > 0)
477  {
478  int result = sem_post(_shared_wake);
479  if (result != 0)
480  throwex SystemException("Failed to release a shared wake semaphore for the named read/write lock!");
481  }
482 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
483  if (!ReleaseSemaphore(_shared_wake, shared_waiters, nullptr))
484  throwex SystemException("Failed to release a shared wake semaphore for the named read/write lock!");
485 #endif
486  }
487 
488  break;
489  }
490  }
491  }
492 
493 private:
494  SharedType<volatile uint64_t> _value;
495 #if (defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)) && !defined(__CYGWIN__)
496  sem_t* _exclusive_wake;
497  sem_t* _shared_wake;
498 #elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
499  HANDLE _exclusive_wake;
500  HANDLE _shared_wake;
501 #endif
502  uint32_t _spin;
503 };
504 
506 
507 NamedRWLock::NamedRWLock(const std::string& name)
508 {
509  // Check implementation storage parameters
510  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
511  static_assert((StorageSize >= sizeof(Impl)), "NamedRWLock::StorageSize must be increased!");
512  static_assert(((StorageAlign % alignof(Impl)) == 0), "NamedRWLock::StorageAlign must be adjusted!");
513 
514  // Create the implementation instance
515  new(&_storage)Impl(name, 4000);
516 }
517 
518 NamedRWLock::~NamedRWLock()
519 {
520  // Delete the implementation instance
521  reinterpret_cast<Impl*>(&_storage)->~Impl();
522 }
523 
524 const std::string& NamedRWLock::name() const { return impl().name(); }
525 
526 bool NamedRWLock::TryLockRead() { return impl().TryLockRead(); }
527 bool NamedRWLock::TryLockWrite() { return impl().TryLockWrite(); }
528 bool NamedRWLock::TryConvertWriteToRead() { return impl().TryConvertWriteToRead(); }
529 
530 bool NamedRWLock::TryLockReadFor(const Timespan& timespan)
531 {
532  // Calculate a finish timestamp
533  Timestamp finish = NanoTimestamp() + timespan;
534 
535  // Try to acquire read lock at least one time
536  if (TryLockRead())
537  return true;
538  else
539  {
540  // Try lock or yield for the given timespan
541  while (NanoTimestamp() < finish)
542  {
543  if (TryLockRead())
544  return true;
545  else
546  Thread::Yield();
547  }
548 
549  // Failed to acquire read lock
550  return false;
551  }
552 }
553 
554 bool NamedRWLock::TryLockWriteFor(const Timespan& timespan)
555 {
556  // Calculate a finish timestamp
557  Timestamp finish = NanoTimestamp() + timespan;
558 
559  // Try to acquire write lock at least one time
560  if (TryLockWrite())
561  return true;
562  else
563  {
564  // Try lock or yield for the given timespan
565  while (NanoTimestamp() < finish)
566  {
567  if (TryLockWrite())
568  return true;
569  else
570  Thread::Yield();
571  }
572 
573  // Failed to acquire write lock
574  return false;
575  }
576 }
577 
578 bool NamedRWLock::TryConvertWriteToReadFor(const Timespan& timespan)
579 {
580  // Calculate a finish timestamp
581  Timestamp finish = NanoTimestamp() + timespan;
582 
583  // Try to convert write lock to read lock at least one time
584  if (TryConvertWriteToRead())
585  return true;
586  else
587  {
588  // Try convert write lock to read lock or yield for the given timespan
589  while (NanoTimestamp() < finish)
590  {
591  if (TryConvertWriteToRead())
592  return true;
593  else
594  Thread::Yield();
595  }
596 
597  // Failed to convert write lock to read lock
598  return false;
599  }
600 }
601 
602 void NamedRWLock::LockRead() { impl().LockRead(); }
603 void NamedRWLock::LockWrite() { impl().LockWrite(); }
604 void NamedRWLock::UnlockRead() { impl().UnlockRead(); }
605 void NamedRWLock::UnlockWrite() { impl().UnlockWrite(); }
606 void NamedRWLock::ConvertWriteToRead() { impl().ConvertWriteToRead(); }
607 
608 } // namespace CppCommon
bool TryConvertWriteToRead()
Try to convert write lock to read lock without block.
void LockRead()
Acquire read lock with block.
bool TryLockWrite()
Try to acquire write lock without block.
bool TryLockRead()
Try to acquire read lock without block.
void LockWrite()
Acquire write lock with block.
const std::string & name() const
Get the read/write lock name.
High resolution timestamp.
Definition: timestamp.h:272
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
Named read/write lock synchronization primitive definition.
C++ Common project definitions.
Definition: token_bucket.h:15
Semaphore synchronization primitive definition.
Shared memory type definition.
Thread definition.
Aligned storage validator definition.