[−][src]Struct spin_sync::Mutex
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
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.
- User calls this method.
- Blocks until this thread acquires the exclusive lock.
- Creates an RAII guard object.
- Wraps the guard in
Result
and returns it. If this mutex has been poisoned, it is wrapped in anErr
; otherwise wrapped in aOk
.
- User accesses to the underlying data through the returned guard. (No other thread can access to the data then.)
- 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.
- User calls this method.
- 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.
- Creates an RAII guard object.
- Wrapps the guard in
Result
and returns it. If this mutex has been poisoned, it is wrapped in anErr
; otherwise wrapped in anOk
.
- User accesses to the underlying data through the returned guard. (No other thread can access to the data then.)
- The guard is dropped (falls out of scope) and the lock is released.
Errors
- If another user is holding this mutex,
TryLockError::WouldBlock
is returned. - If this function call succeeded to acquire the lock, and if another
user panicked while holding this mutex,
TryLockError::Poisoned
is returned.
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
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[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]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,