Struct RwLock

Source
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, G> RwLock<T, G>

Source

pub const fn new(val: T) -> Self

Creates a new spin-based read-write lock with an initial value.

Source§

impl<T: ?Sized, G: SpinGuardian> RwLock<T, G>

Source

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.

Source

pub fn read_arc(self: &Arc<Self>) -> ArcRwLockReadGuard<T, G>

Acquires a read lock through an Arc.

The method is similar to read, but it doesn’t have the requirement for compile-time checked lifetimes of the read guard.

Source

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.

Source

pub fn write_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<T, G>

Acquires a write lock through an Arc.

The method is similar to write, but it doesn’t have the requirement for compile-time checked lifetimes of the lock guard.

Source

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.

Source

pub fn upread_arc(self: &Arc<Self>) -> ArcRwLockUpgradeableGuard<T, G>

Acquires an upgradeable read lock through an Arc.

The method is similar to upread, but it doesn’t have the requirement for compile-time checked lifetimes of the lock guard.

Source

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.

Source

pub fn try_read_arc(self: &Arc<Self>) -> Option<ArcRwLockReadGuard<T, G>>

Attempts to acquire an read lock through an Arc.

The method is similar to try_read, but it doesn’t have the requirement for compile-time checked lifetimes of the lock guard.

Source

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.

Source

fn try_write_arc(self: &Arc<Self>) -> Option<ArcRwLockWriteGuard<T, G>>

Attempts to acquire a write lock through an Arc.

The method is similar to try_write, but it doesn’t have the requirement for compile-time checked lifetimes of the lock guard.

Source

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.

Source

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.

Source

pub fn get_mut(&mut self) -> &mut T

Returns a mutable reference to the underlying data.

This method is zero-cost: By holding a mutable reference to the lock, the compiler has already statically guaranteed that access to the data is exclusive.

Source

pub(super) fn as_ptr(&self) -> *mut T

Returns a raw pointer to the underlying data.

This method is safe, but it’s up to the caller to ensure that access to the data behind it is still safe.

Trait Implementations§

Source§

impl<T: ?Sized + Debug, G> Debug for RwLock<T, G>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

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.

Source§

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>
where Guard: Unpin, T: Unpin + ?Sized,

§

impl<T, Guard> UnwindSafe for RwLock<T, Guard>
where Guard: UnwindSafe, T: UnwindSafe + ?Sized,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows 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) -> R
where R: 'a,

Mutably borrows 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
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<T> Pointee for T

§

type Metadata = ()

The metadata type for pointers and references to this type.
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.