pub struct RwLock<T, Guard> { /* private fields */ }Expand description
Spin-based Read-write Lock
§Overview
This lock allows for multiple readers, or at most one writer to access at any point in time. The writer of this lock has exclusive access to modify the underlying data, while the readers are allowed shared and read-only access.
The writing and reading portions cannot be active simultaneously, when one portion is in progress, the other portion will spin-wait. This is suitable for scenarios where the lock is expected to be held for short periods of time, and the overhead of context switching is higher than the cost of spinning.
In addition to traditional read and write locks, this implementation
provides the upgradeable read lock (upread lock). The upread lock
can be upgraded to write locks atomically, useful in scenarios
where a decision to write is made after reading.
The type parameter T represents the data that this lock is protecting.
It is necessary for T to satisfy Send to be shared across tasks and
Sync to permit concurrent access via readers. The Deref method (and
DerefMut for the writer) is implemented for the RAII guards returned
by the locking methods, which allows for the access to the protected data
while the lock is held.
§Usage
The lock can be used in scenarios where data needs to be read frequently but written to occasionally.
Use upread lock in scenarios where related checking is performed before
modification to effectively avoid deadlocks and improve efficiency.
This lock should not be used in scenarios where lock-holding times are long as it can lead to CPU resource wastage due to spinning.
§About Guard
See the comments of SpinLock.
§Examples
use ostd::sync::RwLock;
let lock = RwLock::new(5)
// many read locks can be held at once
{
let r1 = lock.read();
let r2 = lock.read();
assert_eq!(*r1, 5);
assert_eq!(*r2, 5);
// Upgradeable read lock can share access to data with read locks
let r3 = lock.upread();
assert_eq!(*r3, 5);
drop(r1);
drop(r2);
// read locks are dropped at this point
// An upread lock can only be upgraded successfully after all the
// read locks are released, otherwise it will spin-wait.
let mut w1 = r3.upgrade();
*w1 += 1;
assert_eq!(*w1, 6);
} // upread lock are dropped at this point
{
// Only one write lock can be held at a time
let mut w2 = lock.write();
*w2 += 1;
assert_eq!(*w2, 7);
} // write lock is dropped at this pointImplementations§
Source§impl<T, G> RwLock<T, G>
impl<T, G> RwLock<T, G>
Sourcepub closed spec fn cell_id(self) -> CellId
pub closed spec fn cell_id(self) -> CellId
Returns the unique CellId of the internal PCell<T>.
Sourcepub closed spec fn core_token_id(self) -> Loc
pub closed spec fn core_token_id(self) -> Loc
Sourcepub closed spec fn upread_retract_token_id(self) -> Loc
pub closed spec fn upread_retract_token_id(self) -> Loc
Sourcepub closed spec fn read_guard_token_id(self) -> Loc
pub closed spec fn read_guard_token_id(self) -> Loc
Source§impl<T, G: SpinGuardian> RwLock<T, G>
impl<T, G: SpinGuardian> RwLock<T, G>
Sourcepub exec fn read(&self) -> RwLockReadGuard<'_, T, G>
pub exec fn read(&self) -> RwLockReadGuard<'_, T, G>
Acquires a read lock and spin-wait until it can be acquired.
The calling thread will spin-wait until there are no writers or upgrading upreaders present. There is no guarantee for the order in which other readers or writers waiting simultaneously will obtain the lock.
Sourcepub exec fn write(&self) -> RwLockWriteGuard<'_, T, G>
pub exec fn write(&self) -> RwLockWriteGuard<'_, T, G>
Acquires a write lock and spin-wait until it can be acquired.
The calling thread will spin-wait until there are no other writers, upreaders or readers present. There is no guarantee for the order in which other readers or writers waiting simultaneously will obtain the lock.
Sourcepub exec fn upread(&self) -> RwLockUpgradeableGuard<'_, T, G>
pub exec fn upread(&self) -> RwLockUpgradeableGuard<'_, T, G>
Acquires an upreader and spin-wait until it can be acquired.
The calling thread will spin-wait until there are no other writers, or upreaders. There is no guarantee for the order in which other readers or writers waiting simultaneously will obtain the lock.
Upreader will not block new readers until it tries to upgrade. Upreader and reader do not differ before invoking the upgrade method. However, only one upreader can exist at any time to avoid deadlock in the upgrade method.
Sourcepub exec fn try_read(&self) -> Option<RwLockReadGuard<'_, T, G>>
pub exec fn try_read(&self) -> Option<RwLockReadGuard<'_, T, G>>
Attempts to acquire a read lock.
This function will never spin-wait and will return immediately.
Sourcepub exec fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>>
pub exec fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>>
Attempts to acquire a write lock.
This function will never spin-wait and will return immediately.
Sourcepub exec fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>>
pub exec fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>>
Attempts to acquire an upread lock.
This function will never spin-wait and will return immediately.
Trait Implementations§
impl<T: Send, G> Send for RwLock<T, G>
Because there can be more than one readers to get the T’s immutable ref, so T must be Sync to guarantee the sharing safety.