Struct cros_async::sync::mu::RwLock

source ·
#[repr(align(128))]
pub struct RwLock<T: ?Sized> { raw: RawRwLock, value: UnsafeCell<T>, }
Expand description

A high-level primitive that provides safe, mutable access to a shared resource.

RwLock safely provides both shared, immutable access (via read_lock()) as well as exclusive, mutable access (via lock()) to an underlying resource asynchronously while ensuring fairness with no loss of performance. If you don’t need read_lock() nor fairness, try upstream futures::lock::Mutex instead.

Poisoning

RwLock does not support lock poisoning so if a thread panics while holding the lock, the poisoned data will be accessible by other threads in your program. If you need to guarantee that other threads cannot access poisoned data then you may wish to wrap this RwLock inside another type that provides the poisoning feature. See the implementation of std::sync::Mutex for an example of this. Note futures::lock::Mutex does not support poisoning either.

Fairness

This RwLock implementation does not guarantee that threads will acquire the lock in the same order that they call lock() or read_lock(). However it will attempt to prevent long-term starvation: if a thread repeatedly fails to acquire the lock beyond a threshold then all other threads will fail to acquire the lock until the starved thread has acquired it. Note, on the other hand, futures::lock::Mutex does not guarantee fairness.

Similarly, this RwLock will attempt to balance reader and writer threads: once there is a writer thread waiting to acquire the lock no new reader threads will be allowed to acquire it. However, any reader threads that were already waiting will still be allowed to acquire it.

Examples

use std::sync::Arc;
use std::thread;
use std::sync::mpsc::channel;

use cros_async::{block_on, sync::RwLock};

const N: usize = 10;

// Spawn a few threads to increment a shared variable (non-atomically), and
// let the main thread know once all increments are done.
//
// Here we're using an Arc to share memory among threads, and the data inside
// the Arc is protected with a rwlock.
let data = Arc::new(RwLock::new(0));

let (tx, rx) = channel();
for _ in 0..N {
    let (data, tx) = (Arc::clone(&data), tx.clone());
    thread::spawn(move || {
        // The shared state can only be accessed once the lock is held.
        // Our non-atomic increment is safe because we're the only thread
        // which can access the shared state when the lock is held.
        let mut data = block_on(data.lock());
        *data += 1;
        if *data == N {
            tx.send(()).unwrap();
        }
        // the lock is unlocked here when `data` goes out of scope.
    });
}

rx.recv().unwrap();

Fields§

§raw: RawRwLock§value: UnsafeCell<T>

Implementations§

source§

impl<T> RwLock<T>

source

pub fn new(v: T) -> RwLock<T>

Create a new, unlocked RwLock ready for use.

source

pub fn into_inner(self) -> T

Consume the RwLock and return the contained value. This method does not perform any locking as the compiler will guarantee that there are no other references to self and the caller owns the RwLock.

source§

impl<T: ?Sized> RwLock<T>

source

pub async fn lock(&self) -> RwLockWriteGuard<'_, T>

Acquires exclusive, mutable access to the resource protected by the RwLock, blocking the current thread until it is able to do so. Upon returning, the current thread will be the only thread with access to the resource. The RwLock will be released when the returned RwLockWriteGuard is dropped.

Calling lock() while holding a RwLockWriteGuard or a RwLockReadGuard will cause a deadlock.

Callers that are not in an async context may wish to use the block_on method to block the thread until the RwLock is acquired.

source

pub async fn read_lock(&self) -> RwLockReadGuard<'_, T>

Acquires shared, immutable access to the resource protected by the RwLock, blocking the current thread until it is able to do so. Upon returning there may be other threads that also have immutable access to the resource but there will not be any threads that have mutable access to the resource. When the returned RwLockReadGuard is dropped the thread releases its access to the resource.

Calling read_lock() while holding a RwLockReadGuard may deadlock. Calling read_lock() while holding a RwLockWriteGuard will deadlock.

Callers that are not in an async context may wish to use the block_on method to block the thread until the RwLock is acquired.

source

pub(crate) async fn lock_from_cv(&self) -> RwLockWriteGuard<'_, T>

source

pub(crate) async fn read_lock_from_cv(&self) -> RwLockReadGuard<'_, T>

source

fn unlock(&self)

source

fn read_unlock(&self)

source

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

Trait Implementations§

source§

impl<T: ?Sized + Default> Default for RwLock<T>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<T> From<T> for RwLock<T>

source§

fn from(source: T) -> Self

Converts to this type from the input type.
source§

impl<T: ?Sized + Send> Send for RwLock<T>

source§

impl<T: ?Sized + Send> Sync for RwLock<T>

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for RwLock<T>

§

impl<T: ?Sized> Unpin for RwLock<T>where T: Unpin,

§

impl<T> !UnwindSafe for RwLock<T>

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

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

source§

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

Mutably borrows from an owned value. Read more
source§

impl<T> From<!> for T

source§

fn from(t: !) -> T

Converts to this type from the input type.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere 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.

source§

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

§

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 Twhere U: TryFrom<T>,

§

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.