7#ifndef PXR_BASE_TF_SPIN_RW_MUTEX_H
8#define PXR_BASE_TF_SPIN_RW_MUTEX_H
11#include "pxr/base/tf/api.h"
19PXR_NAMESPACE_OPEN_SCOPE
53 static constexpr int OneReader = 2;
54 static constexpr int WriterFlag = 1;
76 , _acqState(_NotAcquired) {
84 : _mutex(&m), _acqState(_NotAcquired) {}
87 ScopedLock() : _mutex(nullptr), _acqState(_NotAcquired) {}
92 : _mutex(std::exchange(other._mutex,
nullptr))
93 , _acqState(std::exchange(other._acqState, _NotAcquired)) {}
100 if (
this != &other) {
102 _mutex = std::exchange(other._mutex,
nullptr);
103 _acqState = std::exchange(other._acqState, _NotAcquired);
177 _acqState = _ReadAcquired;
187 _acqState = _ReadAcquired;
199 _acqState = _WriteAcquired;
213 _acqState = _WriteAcquired;
228 _acqState = _WriteAcquired;
242 _acqState = _WriteAcquired;
254 _acqState = _ReadAcquired;
261 static constexpr int _NotAcquired = 0;
262 static constexpr int _ReadAcquired = 1;
263 static constexpr int _WriteAcquired = 2;
265 void _ReleaseRead() {
268 _acqState = _NotAcquired;
271 void _ReleaseWrite() {
274 _acqState = _NotAcquired;
288 if (ARCH_LIKELY(!(_lockState.fetch_add(
289 OneReader, std::memory_order_acquire) &
298 _lockState.fetch_sub(OneReader, std::memory_order_release);
320 _lockState.fetch_sub(OneReader, std::memory_order_release);
331 int state = _lockState.fetch_or(WriterFlag, std::memory_order_acquire);
332 if (!(state & WriterFlag)) {
349 return _lockState.compare_exchange_strong(
350 expected, WriterFlag,
351 std::memory_order_acquire,
352 std::memory_order_relaxed);
371 _lockState.fetch_and(~WriterFlag, std::memory_order_release);
384 const auto acquire = std::memory_order_acquire;
385 const auto release = std::memory_order_release;
388 int state = _lockState.fetch_or(WriterFlag, acquire);
389 if (!(state & WriterFlag)) {
393 if (_lockState.fetch_sub(
394 OneReader, release) != (OneReader | WriterFlag)) {
422 _lockState.fetch_add(OneReader - 1, std::memory_order_acq_rel);
430 enum _StagedAcquireWriteState {
443 _StagedAcquireWriteState
444 _StagedAcquireWriteStep(_StagedAcquireWriteState curState) {
447 case _StageNotAcquired:
448 state = _lockState.fetch_or(WriterFlag, std::memory_order_acquire);
449 if (!(state & WriterFlag)) {
452 return state == 0 ? _StageAcquired : _StageAcquiring;
455 return _StageNotAcquired;
456 case _StageAcquiring:
459 return _StageAcquired;
462 return _StageAcquired;
466 TF_API
void _WaitForReaders()
const;
467 TF_API
void _WaitForWriter()
const;
469 std::atomic<int> _lockState;
472PXR_NAMESPACE_CLOSE_SCOPE
This class implements a readers-writer mutex and provides a scoped lock utility.
This class implements a readers-writer spin lock that emphasizes throughput when there is light conte...
bool UpgradeToWriter()
Upgrade this thread's lock on this mutex (which must be a read lock) to a write lock.
bool DowngradeToReader()
Downgrade this mutex, which must be locked for write by this thread, to being locked for read by this...
bool TryAcquireRead()
Attempt to acquire a read lock on this mutex without waiting for writers.
TfSpinRWMutex()
Construct a mutex, initially unlocked.
void ReleaseRead()
Release this thread's read lock on this mutex.
bool TryAcquireWrite()
Attempt to acquire a write lock on this mutex without waiting for other writers, but waiting for any ...
static constexpr DeferAcquire deferAcquire
Tag value for deferred-acquisition ScopedLock construction.
bool TryAcquireWriteIfReleased()
Attempt to acquire a write lock on this mutex only if the mutex is in the fully released state (no re...
void ReleaseWrite()
Release this thread's write lock on this mutex.
void AcquireWrite()
Acquire a write lock on this mutex.
void AcquireRead()
Acquire a read lock on this mutex.
Tag type for constructing a ScopedLock associated with a mutex but not yet acquired.
Stripped down version of diagnostic.h that doesn't define std::string.
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Scoped lock utility class.
bool UpgradeToWriter()
Change this lock's acquisition state from a read lock to a write lock.
ScopedLock(TfSpinRWMutex &m, bool write=true)
Construct a scoped lock for mutex m and acquire either a read or a write lock depending on write.
void Acquire(bool write=true)
Acquire either a read or write lock on this lock's associated mutex depending on write.
ScopedLock()
Construct a scoped lock not associated with a mutex.
ScopedLock(ScopedLock &&other) noexcept
Construct a new lock taking the other lock's mutex association and acquisition state.
bool DowngradeToReader()
Change this lock's acquisition state from a write lock to a read lock.
bool TryAcquireRead()
Try to acquire a read lock on this lock's associated mutex.
void Acquire(TfSpinRWMutex &m, bool write=true)
If the current scoped lock is acquired, Release() it, then associate this lock with m and acquire eit...
bool TryAcquireWrite()
Try to acquire a write lock on this lock's associated mutex without waiting for other writers,...
bool TryAcquire(TfSpinRWMutex &m, bool write=true)
If the current scoped lock is acquired, Release() it, then associate this lock with m and try to acqu...
ScopedLock(TfSpinRWMutex &m, TfSpinRWMutex::DeferAcquire)
Construct a scoped lock associated with mutex m but not yet acquired.
void Release()
Release the currently required lock on the associated mutex.
bool TryAcquireWriteIfReleased()
Try to acquire a write lock on this lock's associated mutex only if the mutex is in the fully release...
ScopedLock & operator=(ScopedLock &&other) noexcept
If this is not the same object as other, Release(), take the other lock's mutex association and acqui...
~ScopedLock()
If this scoped lock is acquired for either read or write, Release() it.
bool TryAcquire(bool write=true)
Try to acquire either a read or a write lock on this lock's associated mutex.
void AcquireWrite()
Acquire a write lock on this lock's associated mutex.
void AcquireRead()
Acquire a read lock on this lock's associated mutex.