CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
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
24namespace CppCommon {
25
27
29
82class 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
101public:
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
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
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
493private:
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
507NamedRWLock::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
518NamedRWLock::~NamedRWLock()
519{
520 // Delete the implementation instance
521 reinterpret_cast<Impl*>(&_storage)->~Impl();
522}
523
524const std::string& NamedRWLock::name() const { return impl().name(); }
525
526bool NamedRWLock::TryLockRead() { return impl().TryLockRead(); }
527bool NamedRWLock::TryLockWrite() { return impl().TryLockWrite(); }
528bool NamedRWLock::TryConvertWriteToRead() { return impl().TryConvertWriteToRead(); }
529
530bool 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
554bool 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
578bool 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
602void NamedRWLock::LockRead() { impl().LockRead(); }
603void NamedRWLock::LockWrite() { impl().LockWrite(); }
604void NamedRWLock::UnlockRead() { impl().UnlockRead(); }
605void NamedRWLock::UnlockWrite() { impl().UnlockWrite(); }
606void NamedRWLock::ConvertWriteToRead() { impl().ConvertWriteToRead(); }
607
608} // namespace CppCommon
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.
Semaphore synchronization primitive definition.
Shared memory type definition.
Thread definition.
Aligned storage validator definition.