Struct bitflags::__core::sync::Mutex
[−]
[src]
pub struct Mutex<T> where T: ?Sized {
// some fields omitted
}
1.0.0A mutual exclusion primitive useful for protecting shared data
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 lock. Once a mutex is poisoned, all other threads are unable to access the data by default as it is likely tainted (some invariant is not being upheld).
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
use std::sync::{Arc, Mutex}; use std::thread; use std::sync::mpsc::channel; 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 mutex. let data = Arc::new(Mutex::new(0)); let (tx, rx) = channel(); for _ in 0..10 { let (data, tx) = (data.clone(), 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. // // We unwrap() the return value to assert that we are not expecting // threads to ever fail while holding the lock. let mut data = data.lock().unwrap(); *data += 1; if *data == N { tx.send(()).unwrap(); } // the lock is unlocked here when `data` goes out of scope. }); } rx.recv().unwrap();
To recover from a poisoned mutex:
use std::sync::{Arc, Mutex}; use std::thread; let lock = Arc::new(Mutex::new(0_u32)); let lock2 = lock.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 = lock2.lock().unwrap(); // This panic while holding the lock (`_guard` is in scope) will poison // the mutex. panic!(); }).join(); // The lock is poisoned by this point, but the returned result can be // pattern matched on to return the underlying guard on both branches. let mut guard = match lock.lock() { Ok(guard) => guard, Err(poisoned) => poisoned.into_inner(), }; *guard += 1;