Mutex<T>
- Rust course
- Advanced
- Lesson 14/81
- 4 min
Do mutual exclusion with Mutex<T>.
Mutex<T>
Mutex<T> (mutual exclusion) lets only one thread access the data at a time. lock() returns a guard; the lock is held while the guard lives and released automatically when the guard is dropped:
use std::sync::{Arc, Mutex};
let sayac = Arc::new(Mutex::new(0));
let mut h = Vec::new();
for _ in 0..8 {
let s = Arc::clone(&sayac);
h.push(thread::spawn(move || {
for _ in 0..100 {
*s.lock().unwrap() += 1;
}
}));
}In Rust the data lives inside the mutex; there's no way to reach the data without taking the lock. This makes the "forgot to lock" bug impossible.
Lock duration and deadlock
Holding the guard long makes other threads wait. If two locks are taken in different orders, two threads can wait for each other forever (deadlock). Rules: keep the lock short, don't do slow work under the lock, always take multiple locks in the same order:
{
let mut veri = kilitli.lock().unwrap();
veri.push(1);
} // the guard is dropped here, the lock opens
yavas_islem(); // without holding the lockRust prevents data races, but a deadlock is a logic bug and the compiler doesn't catch it.
Practice Shared counter
Share an Arc<Mutex<i32>> counter with 8 threads; let each thread increment it 100 times. After joining all threads, print the final value.
Starter code
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// buraya yaz
}Sample solution
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let sayac = Arc::new(Mutex::new(0));
let mut h = Vec::new();
for _ in 0..8 {
let s = Arc::clone(&sayac);
h.push(thread::spawn(move || {
for _ in 0..100 {
*s.lock().unwrap() += 1;
}
}));
}
for t in h {
t.join().unwrap();
}
println!("{}", *sayac.lock().unwrap());
}Expected output
800
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Why does <code>lock()</code> return a <code>Result</code>?
- For timeouts
- Convention
- If a thread holding the lock panicked, the mutex becomes "poisoned" Correct answer
- The lock might not be obtainable
Explanation: Poisoning is a warning that the data may be inconsistent due to an interrupted update.
2 Take the lock
*s.____().unwrap() += 1;
*s.lock().unwrap() += 1;
Explanation: Mutex::lock returns a guard; the data is changed through the guard.
3 Concept and meaning
| Term | Meaning |
|---|---|
Mutex::lock() |
MutexGuard |
guard drop |
Lock released |
poisoned |
The holder panicked |
deadlock |
Mutual waiting |