Shared-State Concurrency
Mutex
- Mutual exclusion (mutex) is a mechanism to manage multiple threads accessing the same memory region. Only one thread can access a piece of data at a time.
- To access data in a mutex, a thread signals that wants to acquire the mutex lock. Lock is a data structure, part of the mutex, that keeps track of who’s accessing the data at any given time.
- Acquiring the lock must happen before using the data.
- A thread must unlock the data after using, so other threads can access it.
- This is an example of Mutex in action.
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {m:?}");
}
- After accessing the data, the thread gets a mutable reference to the value inside the lock.
- Type system ensures that a thread acquires the lock before using it, because
m
if of type Mutex<i32>
- In Rust, the Mutex type panics if someone else is holding the lock and a thread tries to get the hold of the lock.
Atomic Reference Counting
- [[Rust book - Rc]] is not enough to share mutex references along threads, since it doesn’t use any concurrency primitives, which can lead to make sure changes to counter can’t be interrupted by another thread
- Arc uses a concurrency primitive called atomic, which makes Mutex shareable across threads
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}