|
SpECTRE
v2025.08.19
|
A two-state spinlock that allows multiple readers of a shared resource to acquire the lock simultaneously. More...
#include <MultiReaderSpinlock.hpp>
Public Member Functions | |
| MultiReaderSpinlock (const MultiReaderSpinlock &)=delete | |
| MultiReaderSpinlock & | operator= (const MultiReaderSpinlock &)=delete |
| MultiReaderSpinlock (MultiReaderSpinlock &&)=delete | |
| MultiReaderSpinlock & | operator= (MultiReaderSpinlock &&)=delete |
| void | read_lock () noexcept |
| Acquire the lock in a reader state. More... | |
| void | read_unlock () noexcept |
| Release the lock from a reader state. More... | |
| void | write_lock () noexcept |
| Acquire the lock in a writer state. More... | |
| void | write_unlock () noexcept |
| Release the lock from a reader state. | |
A two-state spinlock that allows multiple readers of a shared resource to acquire the lock simultaneously.
A spinlock (i.e. a non-yielding lock) that can be used to guard a resource where multiple threads can safely perform some types of operations (e.g. reader entries from a container), while only one thread can safely perform other types of operations (e.g. modifying the container).
We lock by using a std::atomic<std::int64_t> (a signed integer). The lock is not locked if the integer is 0. It is read-locked if it is positive and write-locked if it is negative. To read-lock we first check that the integer is non-negative and then fetch_add(1, std::memory_order_acq_rel), then check that the number before the increment is non-negative. The reason for the second check is that between checking that the lock is not write-locked and the fetch_add() operation, it could be write-locked by another thread. To write-lock, we check that the integer is 0 and if so we set it to std::numeric_limits<std::int64_t>::lowest() (i.e. -2^{63}). We achieve this by using a compare_exchange_strong() with failure memory order relaxed and success memory order acq_rel. This guarantees that different threads synchronize using the lock.
A thread read-unlocks the lock using a fetch_sub(1, std::memory_order_acq_rel) operation.
A thread write-unlocks the lock using a store(0, std::memory_order_release) operation.
|
inlinenoexcept |
Acquire the lock in a reader state.
|
inlinenoexcept |
Release the lock from a reader state.
|
inlinenoexcept |
Acquire the lock in a writer state.
Once acquired, no other thread can acquire the lock in either a read or a write state until this thread unlocks it.