Struct spin_sync::RwLock[][src]

pub struct RwLock<T: ?Sized> { /* fields omitted */ }

A reader-writer lock.

It behaves like std::sync::RwLock except for using spinlock. What is more, the constructor is a const function; i.e. it is possible to declare static RwLock<T> variable as long as the inner data can be built statically.

This type of lock allows either a number of readers or at most one writer at the same time. Readers are allowed read-only access (shared access) to the underlying data while the writer is allowed read/write access (exclusive access.)

In comparison, a Mutex does not distinguish between readers and writers, therefore blocking any threads waiting for the lock to become available. An RwLock will allow any number of readers to acquire the lock as long as a writer is not holding the lock.

There is no priority difference with respect to the ordering of whether contentious readers or writers will acquire the lock first.

Poisoning

An RwLock, like Mutex, will become poisoned on a panic. Note, however, that an RwLock may only be poisoned if a panic occurs while it is locked exclusively (write mode). If a panic occurs in any reader, then the lock will not be poisoned.

Examples

Create a variable protected by a RwLock, increment it by 2 in worker threads at the same time, and check the variable was updated rightly.

use spin_sync::RwLock;
use std::sync::Arc;
use std::thread;

const WORKER_NUM: usize = 10;
let mut handles = Vec::with_capacity(WORKER_NUM);

// We can declare static RwLock<usize> variable because RwLock::new is a const function.
static RWLOCK: RwLock<usize> = RwLock::new(0);

// Create worker threads to inclement the value by 2.
for _ in 0..WORKER_NUM {
    let handle = thread::spawn(move || {
        let mut num = RWLOCK.write().unwrap();
        *num += 2;
    });

    handles.push(handle);
}

// Make sure the value is always multipile of 2 even if some worker threads
// are working.
//
// Enclosing the lock with `{}` to drop it before waiting for the worker
// threads; otherwise, deadlocks could be occurred.
{
    let num = RWLOCK.read().unwrap();
    assert_eq!(0, *num % 2);
}

// Wait for the all worker threads are finished.
for handle in handles {
    handle.join().unwrap();
}

// Make sure the value is incremented by 2 times the worker count.
let num = RWLOCK.read().unwrap();
assert_eq!(2 * WORKER_NUM, *num);

Implementations

impl<T> RwLock<T>[src]

pub const fn new(t: T) -> Self[src]

Creates a new instance in unlocked state ready for use.

Examples

Declare as a static variable.

use spin_sync::RwLock;

static LOCK: RwLock<i32> = RwLock::new(5);

Declare as a local variable.

use spin_sync::RwLock;

let lock = RwLock::new(5);

pub fn into_inner(self) -> LockResult<T>[src]

Consumes this instance and returns the underlying data.

Note that this method won't acquire any lock because we know there is no other references to self.

Errors

If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.

Examples

use spin_sync::RwLock;

let rwlock = RwLock::new(0);
assert_eq!(0, rwlock.into_inner().unwrap());

impl<T: ?Sized> RwLock<T>[src]

pub const MAX_READ_LOCK_COUNT: u64[src]

The maximum shared read locks of each instance.

pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>>[src]

Blocks the current thread until acquiring a shared read lock, and returns an RAII guard object.

The actual flow will be as follows.

  1. User calls this method.
    1. Blocks until this thread acquires a shared read lock (i.e. until the exclusive write lock is held.)
    2. Creates an RAII guard object.
    3. Wrapps the guard in Result and returns it. If this instance has been poisoned, it is wrapped in an Err; otherwise wrapped in an Ok.
  2. User accesses to the underlying data to read through the guard. (No write access is then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Errors

If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.

Panics

This method panics if MAX_READ_LOCK_COUNT shared locks are.

Examples

use spin_sync::RwLock;

let lock = RwLock::new(1);

let guard1 = lock.read().unwrap();
assert_eq!(1, *guard1);

let guard2 = lock.read().unwrap();
assert_eq!(1, *guard2);

pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>>[src]

Attempts to acquire a shared read lock and returns an RAII guard object if succeeded.

Behaves like read except for this method returns an error immediately if the exclusive write lock is being held.

This function does not block.

The actual flow will be as follows.

  1. User calls this method.
    1. Tries to acquire a shared read lock. If failed (i.e. if the exclusive write lock is being held,) returns an error immediately and this flow is finished here.
    2. Creates an RAII guard object.
    3. Wrapps the guard in Result and returns it. If this instance has been poisoned, it is wrapped in an Err; otherwise wrapped in an Ok.
  2. User accesses to the underlying data to read through the guard. (No write access is at then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Panics

This method panics if MAX_READ_LOCK shared read locks are.

Errors

  • If another user is holding the exclusive write lock, TryLockError::WouldBlock is returned.
  • If this method call succeeded to acquire a shared read lock, and if another user had panicked while holding the exclusive write lock, TryLockError::Poisoned is returned.

Examples

use spin_sync::RwLock;

let lock = RwLock::new(1);

let guard0 = lock.try_read().unwrap();
assert_eq!(1, *guard0);

let guard1 = lock.try_read().unwrap();
assert_eq!(1, *guard1);

pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>>[src]

Attempts to acquire the exclusive write lock and returns an RAII guard object if succeeded.

Behaves like write except for this method returns an error immediately if any other lock (either read lock or write lock) is being held.

This method does not block.

The actual flow will be as follows.

  1. User calls this method.
    1. Tries to acquire the exclusive write lock. If failed (i.e. if any other lock is being held,) returns an error immediately and this flow is finished here.
    2. Creates an RAII guard object.
    3. Wraps the guard in Result and returns it. If this instance has been poisoned, it is wrapped in an Err; otherwise wrapped in an Ok.
  2. User accesses to the underlying data to read/write through the guard. (No other access is then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Errors

  • If another user is holding any other lock (either read lock or write lock), TryLockError::WouldBlock is returned.
  • If this method call succeeded to acquire the lock, and if another user had panicked while holding the exclusive write lock, TryLockError::Poisoned is returned.

Examples

use spin_sync::RwLock;

let lock = RwLock::new(1);

let mut guard = lock.try_write().unwrap();
assert_eq!(1, *guard);

*guard += 1;
assert_eq!(2, *guard);

assert!(lock.try_write().is_err());
assert!(lock.try_read().is_err());

pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>>[src]

Blocks the current thread until acquiring the exclusive write lock, and returns an RAII guard object.

The actual flow will be as follows.

  1. User calls this method.
    1. Blocks until this thread acquires the exclusive write lock (i.e. until any other lock is held.)
    2. Creates an RAII guard object.
    3. Wrapps the guard in Result and returns it. If this instance has been poisoned, it is wrapped in an Err; otherwise wrapped in an Ok.
  2. User accesses to the underlying data to read/write through the guard. (No other access is then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Errors

If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.

Examples

use spin_sync::RwLock;

let lock = RwLock::new(0);

let mut guard = lock.write().unwrap();
assert_eq!(0, *guard);

*guard += 1;
assert_eq!(1, *guard);

assert_eq!(true, lock.try_read().is_err());
assert_eq!(true, lock.try_write().is_err());

pub fn is_poisoned(&self) -> bool[src]

Determines whether the lock is poisoned or not.

Warning

This function won't acquire any lock. If another thread is active, the rwlock can become poisoned at any time. You should not trust a false value for program correctness without additional synchronization.

Examples

use spin_sync::RwLock;
use std::sync::Arc;
use std::thread;

let lock = Arc::new(RwLock::new(0));
assert_eq!(false, lock.is_poisoned());

{
    let lock = lock.clone();

    let _ = thread::spawn(move || {
        // This panic while holding the lock (`_guard` is in scope) will poison
        // the instance.
        let _guard = lock.write().unwrap();
        panic!("Poison here");
    }).join();
}

assert_eq!(true, lock.is_poisoned());

pub fn get_mut(&mut self) -> LockResult<&mut T>[src]

Returns a mutable reference to the underlying data.

Note that this method won't acquire any lock because we know there is no other references to self.

Errors

If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.

Examples

use spin_sync::RwLock;

let mut lock = RwLock::new(0);
*lock.get_mut().unwrap() = 10;
assert_eq!(*lock.read().unwrap(), 10);

Trait Implementations

impl<T: ?Sized + Debug> Debug for RwLock<T>[src]

impl<T: Default> Default for RwLock<T>[src]

impl<T> From<T> for RwLock<T>[src]

impl<T: ?Sized> RefUnwindSafe for RwLock<T>[src]

impl<T: ?Sized + Send> Send for RwLock<T>[src]

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

impl<T: ?Sized> UnwindSafe for RwLock<T>[src]

Auto Trait Implementations

impl<T: ?Sized> Unpin for RwLock<T> where
    T: Unpin
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<!> for T[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.