pub struct RwLock<T: ?Sized, Guard = PreemptDisabled> {
guard: PhantomData<Guard>,
lock: AtomicUsize,
val: UnsafeCell<T>,
}
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 point
Fields§
§guard: PhantomData<Guard>
§lock: AtomicUsize
The internal representation of the lock state is as follows:
- Bit 63: Writer lock.
- Bit 62: Upgradeable reader lock.
- Bit 61: Indicates if an upgradeable reader is being upgraded.
- Bits 60-0: Reader lock count.
val: UnsafeCell<T>
Implementations§
Source§impl<T: ?Sized, G: SpinGuardian> RwLock<T, G>
impl<T: ?Sized, G: SpinGuardian> RwLock<T, G>
Sourcepub fn read(&self) -> RwLockReadGuard<'_, T, G>
pub 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 fn read_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<T, G>
pub fn read_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<T, G>
Sourcepub fn write(&self) -> RwLockWriteGuard<'_, T, G>
pub 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 fn write_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<T, G>
pub fn write_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<T, G>
Sourcepub fn upread(&self) -> RwLockUpgradeableGuard<'_, T, G>
pub 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 upgread method. However, only one upreader can exist at any time to avoid deadlock in the upgread method.
Sourcepub fn upread_arc(self: &Arc<Self>) -> ArcRwLockUpgradeableGuard<T, G>
pub fn upread_arc(self: &Arc<Self>) -> ArcRwLockUpgradeableGuard<T, G>
Sourcepub fn try_read(&self) -> Option<RwLockReadGuard<'_, T, G>>
pub 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 fn try_read_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<T, G>>
pub fn try_read_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<T, G>>
Sourcepub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>>
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>>
Attempts to acquire a write lock.
This function will never spin-wait and will return immediately.
Sourcefn try_write_arc(self: &Arc<Self>) -> Option<ArcRwLockWriteGuard<T, G>>
fn try_write_arc(self: &Arc<Self>) -> Option<ArcRwLockWriteGuard<T, G>>
Sourcepub fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>>
pub fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>>
Attempts to acquire an upread lock.
This function will never spin-wait and will return immediately.
Sourcepub fn try_upread_arc(
self: &Arc<Self>,
) -> Option<ArcRwLockUpgradeableGuard<T, G>>
pub fn try_upread_arc( self: &Arc<Self>, ) -> Option<ArcRwLockUpgradeableGuard<T, G>>
Attempts to acquire an upgradeable read lock through an Arc
.
The method is similar to try_upread
, but it doesn’t have the requirement
for compile-time checked lifetimes of the lock guard.
Trait Implementations§
impl<T: ?Sized + 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.
impl<T: ?Sized + Send + Sync, G> Sync for RwLock<T, G>
Auto Trait Implementations§
impl<T, Guard = PreemptDisabled> !Freeze for RwLock<T, Guard>
impl<T, Guard = PreemptDisabled> !RefUnwindSafe for RwLock<T, Guard>
impl<T, Guard> Unpin for RwLock<T, Guard>
impl<T, Guard> UnwindSafe for RwLock<T, Guard>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.§impl<T> Pointee for T
impl<T> Pointee for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.