Summary - Concurrency
- Rust course
- Advanced
- Lesson 18/81
- 5 min
Combine thread, Arc and Mutex to build a parallel counter.
Concurrency summary
thread::spawn starts threads with owning (move) closures; thread::scope allows borrowing. For sharing use Arc, and for mutation put a Mutex (single access) or RwLock (many readers/one writer) inside. Thanks to the Send and Sync marker traits, data races are prevented at compile time; a deadlock, however, is a logic bug and is prevented by lock ordering.
Parallel word count
Each text is counted on a separate thread, and the result is added to the shared map in a single step under the lock:
let sayim = Arc::new(Mutex::new(HashMap::new()));
thread::scope(|s| {
for metin in &metinler {
let sayim = Arc::clone(&sayim);
s.spawn(move || {
let mut yerel: HashMap<String, usize> = HashMap::new();
for k in metin.split_whitespace() {
*yerel.entry(k.to_string()).or_insert(0) += 1;
}
let mut ortak = sayim.lock().unwrap();
for (k, n) in yerel {
*ortak.entry(k).or_insert(0) += n;
}
});
}
});Practice Parallel count
Count the texts ["elma armut", "elma", "armut kiraz elma"] on separate threads as above. Collect the result into a vector, sort and print it with {:?}.
Starter code
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// buraya yaz
}Sample solution
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let metinler = ["elma armut", "elma", "armut kiraz elma"];
let sayim = Arc::new(Mutex::new(HashMap::new()));
thread::scope(|s| {
for metin in &metinler {
let sayim = Arc::clone(&sayim);
s.spawn(move || {
let mut yerel: HashMap<String, usize> = HashMap::new();
for k in metin.split_whitespace() {
*yerel.entry(k.to_string()).or_insert(0) += 1;
}
let mut ortak = sayim.lock().unwrap();
for (k, n) in yerel {
*ortak.entry(k).or_insert(0) += n;
}
});
}
});
let mut v: Vec<(String, usize)> = sayim.lock().unwrap().clone().into_iter().collect();
v.sort();
println!("{:?}", v);
}Expected output
[("armut", 2), ("elma", 3), ("kiraz", 1)]
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 In a parallel word count, why is it faster for each thread to fill its own local HashMap and merge at the end?
- It uses less memory
- There's no difference
- Waiting on a shared lock for every word disappears Correct answer
- HashMap isn't thread safe
Explanation: Lock contention kills parallelism; minimizing shared state is the main rule.
2 Shared map
let sayim = Arc::new(____::new(HashMap::new()));
let sayim = Arc::new(Mutex::new(HashMap::new()));
Explanation: Arc<Mutex<T>> for mutable sharing across threads.
3 Group summary
| Term | Meaning |
|---|---|
thread::scope |
Borrowing threads |
Mutex |
Single access |
RwLock |
Many readers |
Send/Sync |
Compile-time safety |