pub struct Mutex<T: ?Sized, R> { /* private fields */ }barging only.Expand description
A 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.
Examples
use std::sync::Arc;
use std::thread;
use std::sync::mpsc::channel;
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
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(SpinMutex::new(0));
let (tx, rx) = channel();
for _ in 0..N {
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();
*data += 1;
if *data == N {
tx.send(()).unwrap();
}
// the lock is unlocked here when `data` goes out of scope.
});
}
rx.recv().unwrap();Implementations§
source§impl<T, R> Mutex<T, R>
impl<T, R> Mutex<T, R>
sourcepub const fn new(value: T) -> Self
pub const fn new(value: T) -> Self
Creates a new mutex in an unlocked state ready for use.
Examples
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
const MUTEX: SpinMutex<i32> = SpinMutex::new(0);
let mutex = SpinMutex::new(0);sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
Consumes this mutex, returning the underlying data.
Examples
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = SpinMutex::new(0);
assert_eq!(mutex.into_inner(), 0);source§impl<T: ?Sized, R: Relax> Mutex<T, R>
impl<T: ?Sized, R: Relax> Mutex<T, R>
sourcepub fn lock(&self) -> MutexGuard<'_, T, R>
pub fn lock(&self) -> MutexGuard<'_, T, R>
Acquires this mutex, blocking the current thread until it is able to do so.
This function will block the local thread until it is available to acquire
the mutex. Upon returning, the thread is the only thread with the lock
held. An RAII guard is returned to allow scoped unlock of the lock. When
the guard goes out of scope, the mutex will be unlocked. To acquire a MCS
lock, it’s also required a mutably borrowed queue node, which is a record
that keeps a link for forming the queue, see MutexNode.
This function will block if the lock is unavailable.
Examples
use std::sync::Arc;
use std::thread;
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = Arc::new(SpinMutex::new(0));
let c_mutex = Arc::clone(&mutex);
thread::spawn(move || {
*c_mutex.lock() = 10;
})
.join().expect("thread::spawn failed");
assert_eq!(*mutex.lock(), 10);sourcepub fn lock_with<F, Ret>(&self, f: F) -> Retwhere
F: FnOnce(MutexGuard<'_, T, R>) -> Ret,
pub fn lock_with<F, Ret>(&self, f: F) -> Retwhere
F: FnOnce(MutexGuard<'_, T, R>) -> Ret,
Acquires this mutex and then runs the closure against its guard.
This function will block the local thread until it is available to acquire the mutex. Upon acquiring the mutex, the user provided closure will be executed against the mutex guard. Once the guard goes out of scope, it will unlock the mutex.
This function will block if the lock is unavailable.
Examples
use std::sync::Arc;
use std::thread;
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = Arc::new(SpinMutex::new(0));
let c_mutex = Arc::clone(&mutex);
thread::spawn(move || {
c_mutex.lock_with(|mut guard| *guard = 10);
})
.join().expect("thread::spawn failed");
assert_eq!(mutex.lock_with(|guard| *guard), 10);Borrows of the guard or its data cannot escape the given closure.
use mcslock::barging::spins::Mutex;
let mutex = Mutex::new(1);
let data = mutex.lock_with(|guard| &*guard);source§impl<T: ?Sized, R> Mutex<T, R>
impl<T: ?Sized, R> Mutex<T, R>
sourcepub fn try_lock(&self) -> Option<MutexGuard<'_, T, R>>
pub fn try_lock(&self) -> Option<MutexGuard<'_, T, R>>
Attempts to acquire this mutex without blocking the thread.
If the lock could not be acquired at this time, then None is returned.
Otherwise, an RAII guard is returned. The lock will be unlocked when the
guard is dropped. To acquire a MCS lock, it’s also required a mutably
borrowed queue node, which is a record that keeps a link for forming the
queue, see MutexNode.
This function does not block.
Examples
use std::sync::Arc;
use std::thread;
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = Arc::new(SpinMutex::new(0));
let c_mutex = Arc::clone(&mutex);
thread::spawn(move || {
let mut guard = c_mutex.try_lock();
if let Some(mut guard) = guard {
*guard = 10;
} else {
println!("try_lock failed");
}
})
.join().expect("thread::spawn failed");
assert_eq!(*mutex.lock(), 10);sourcepub fn try_lock_with<F, Ret>(&self, f: F) -> Ret
pub fn try_lock_with<F, Ret>(&self, f: F) -> Ret
Attempts to acquire this mutex and then runs a closure against its guard.
If the lock could not be acquired at this time, then a None value is
given back as the closure argument. If the lock has been acquired, then
a Some value with the mutex guard is given instead. The lock will be
unlocked when the guard is dropped.
This function does not block.
Examples
use std::sync::Arc;
use std::thread;
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = Arc::new(SpinMutex::new(0));
let c_mutex = Arc::clone(&mutex);
thread::spawn(move || {
c_mutex.try_lock_with(|guard| {
if let Some(mut guard) = guard {
*guard = 10;
} else {
println!("try_lock failed");
}
});
})
.join().expect("thread::spawn failed");
assert_eq!(mutex.lock_with(|guard| *guard), 10);Borrows of the guard or its data cannot escape the given closure.
use mcslock::barging::spins::Mutex;
let mutex = Mutex::new(1);
let data = mutex.try_lock_with(|guard| &*guard.unwrap());sourcepub fn is_locked(&self) -> bool
pub fn is_locked(&self) -> bool
Returns true if the lock is currently held.
This method does not provide any synchronization guarantees, so its only useful as a heuristic, and so must be considered not up to date.
Example
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mutex = SpinMutex::new(0);
let guard = mutex.lock();
drop(guard);
assert_eq!(mutex.is_locked(), false);sourcepub fn get_mut(&mut self) -> &mut T
pub fn get_mut(&mut self) -> &mut T
Returns a mutable reference to the underlying data.
Since this call borrows the Mutex mutably, no actual locking needs to
take place - the mutable borrow statically guarantees no locks exist.
Examples
use mcslock::barging::Mutex;
use mcslock::relax::Spin;
type SpinMutex<T> = Mutex<T, Spin>;
let mut mutex = SpinMutex::new(0);
*mutex.get_mut() = 10;
assert_eq!(*mutex.lock(), 10);Trait Implementations§
source§impl<R: Relax> RawMutex for Mutex<(), R>
impl<R: Relax> RawMutex for Mutex<(), R>
§type GuardMarker = GuardSend
type GuardMarker = GuardSend
Send. Use
one of the GuardSend or GuardNoSend helper types here.