[Day11] Read Rust Atomics and Locks - Rust's Mutex
by Mara Bos
At Topics: Chapter 1. Basics of Rust Concurrency
Recall
Mutex and RwLock
- An
RwLock
or reader-writer lock is the concurrent version of aRefCell
- An
RwLock<T>
holds aT
and tracks any outstanding borrows. - When conflicting borrows happen, it does not panic. Instead, it blocks the current thread (putting it to sleep) and waits for conflicting borrows to disappear.
- Borrowing the contents of an
RwLock
is called locking RwLock
keeps tracking shared and exclusive borrows- A
Mutex
is very similar toRwLock
, but it only allows exclusive borrows.
Notes
Locking: Mutexes and RwLocks
The most commonly used tool for sharing (mutable) data between threads is a mutex (mutual exclusion): Data will only be used by a thread at a time
Conceptually,
- A mutex has only two states: locked and unlocked
- When a thread locks an unlocked mutex, the mutex is marked as locked and the same thread can immediately continue.
- When a thread attempts to lock an already locked mutex, that operation will block and is put to sleep.
- Unlocking is only possible to be done by the same thread that locked it.
- Unlocking will wake up one of those waiting threads, after mutex is unlocked.
- The only thread having the mutex locked can access the data
Rust’s Mutex
std::sync::Mutex<T>
T
can only be accessed through the mutex- It does not have an
unlock()
method, because a locked mutex can only be unlocked by the thread that locked it - While using a mutex can ensure serialized execution, it also negates the advantages of parallelism
use std::sync::Mutex; fn main() { let n = Mutex::new(0); thread::scope(|s| { for _ in 0..10 { // spawn ten threads s.spawn(|| { let mut guard = n.lock().unwrap(); lock the mutex to obtain `MutexGuard` for _ in 0..100 { *guard += 1; } }); // The guard is implicitly dropped right after } }); // The into_inner method takes ownership of the mutex, which guarantees that nothing else can have a reference to the mutex anymore, making locking unnecessary. (remove the protection) assert_eq!(n.into_inner().unwrap(), 1000); }