[][src]Struct spin_sync::Mutex

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

A mutual exclusion primitive useful for protecting shared data.

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

This mutex will block threads waiting for the lock to become available. The mutex can also be statically initialized or created via a new constructor. Each mutex has a type parameter which represents the data that it is protecting. The data can only be accessed through the RAII guards returned from lock and try_lock, which guarantees that the data is only ever accessed when the mutex is locked.

Poisoning

The mutexes in this module implement a strategy called "poisoning" where a mutex is considered poisoned whenever a thread panics while holding the mutex. Once a mutex is poisoned, all other threads are unable to access the data by default as it is likely tainted.

For a mutex, this means that the lock and try_lock methods return a Result which indicates whether a mutex has been poisoned or not. Most usage of a mutex will simply unwrap() these results, propagating panics among threads to ensure that a possibly invalid invariant is not witnessed.

A poisoned mutex, however, does not prevent all access to the underlying data. The PoisonError type has an into_inner method which will return the guard that would have otherwise been returned on a successful lock. This allows access to the data, despite the lock being poisoned.

Examples

Protect a variable (non-atomically) and update it in worker threads.

use spin_sync::Mutex;
use std::thread;

const WORKER_NUM: usize = 10;

// We can declare static Mutex<usize> variable because Mutex::new is const.
static MUTEX: Mutex<usize> = Mutex::new(0);

let mut handles = Vec::with_capacity(WORKER_NUM);

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

    handles.push(handle);
}

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

// Make sure the value is incremented by the worker count.
let num = MUTEX.lock().unwrap();
assert_eq!(WORKER_NUM, *num);

To recover from a poisoned mutex:

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

// Like std::sync::Mutex, it can be declare as local variable, of course.
let mutex = Arc::new(Mutex::new(0));
let c_mutex = mutex.clone();

let _ = thread::spawn(move || -> () {
    // This thread will acquire the mutex first, unwrapping the result of
    // `lock` because the lock has not been poisoned.
    let _guard = c_mutex.lock().unwrap();

    // This panic while holding the lock (`_guard` is in scope) will poison
    // the mutex.
    panic!();
}).join();

// Here, the mutex has been poisoned.
assert_eq!(true, mutex.is_poisoned());

// The returned result can be pattern matched on to return the underlying
// guard on both branches.
let mut guard = match mutex.lock() {
    Ok(guard) => guard,
    Err(poisoned) => poisoned.into_inner(),
};

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

Implementations

impl<T> Mutex<T>[src]

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

Creates a new mutex in an unlocked state ready for use.

unlike to std::sync::Mutex::new, this is a const function. It can be use for static variable.

Examples

Declare as a static variable.

use spin_sync::Mutex;

static MUTEX: Mutex<i32> = Mutex::new(0);

Declare as a local variable.

use spin_sync::Mutex;

let mutex = Mutex::new(0);

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

Consumes this mutex 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 this mutex, this call wraps the result in an error and returns it.

Examples

use spin_sync::Mutex;

let mutex = Mutex::new(0);
assert_eq!(0, mutex.into_inner().unwrap());

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

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

Blocks the current thread until acquiring the 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 lock.
    2. Creates an RAII guard object.
    3. Wraps the guard in Result and returns it. If this mutex has been poisoned, it is wrapped in an Err; otherwise wrapped in a Ok.
  2. User accesses to the underlying data through the returned guard. (No other thread can access to the data then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Errors

If another user panicked while holding this mutex, this method call wraps the guard in an error and returns it.

Examples

use spin_sync::Mutex;

let mutex = Mutex::new(0);

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

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

assert_eq!(true, mutex.try_lock().is_err());

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

Attempts to acquire this lock and returns an RAII guard object if succeeded.

Behaves like lock except for this method returns an error immediately if another user is holding the lock.

This method does not block.

The actual flow will be as follows.

  1. User calls this method.
    1. Tries to acquire the lock. If failed (i.e. if the 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 mutex has been poisoned, it is wrapped in an Err; otherwise wrapped in an Ok.
  2. User accesses to the underlying data through the returned guard. (No other thread can access to the data then.)
  3. The guard is dropped (falls out of scope) and the lock is released.

Errors

Examples

use spin_sync::Mutex;

let mutex = Mutex::new(0);

// try_lock() fails while another guard is.
// It doesn't cause a deadlock.
{
    let _guard = mutex.lock().unwrap();
    assert_eq!(true, mutex.try_lock().is_err());
}

// try_lock() behaves like lock() if no other guard is.
{
    let mut guard = mutex.try_lock().unwrap();
    assert_eq!(true, mutex.try_lock().is_err());
    *guard += 1;
}

let guard = mutex.try_lock().unwrap();
assert_eq!(1, *guard);

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

Determines whether the mutex is poisoned or not.

Warnings

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

This behavior is same to std::sync::Mutex::is_poisoned().

Examples

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

let mutex = Arc::new(Mutex::new(0));
assert_eq!(false, mutex.is_poisoned());

// Panic and poison the mutex.
{
    let mutex = mutex.clone();

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

assert_eq!(true, mutex.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 this mutex, this method call wraps the result in an error and returns it.

Examples

use spin_sync::Mutex;

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

Trait Implementations

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

impl<T: ?Sized + Default> Default for Mutex<T>[src]

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

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

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

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

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

Auto Trait Implementations

impl<T: ?Sized> Unpin for Mutex<T> where
    T: Unpin

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.