Threads: Fearless Concurrency
Rust's ownership system makes concurrent programming safe. Data races are impossible - the compiler prevents them at compile time.
use std::thread;
use std::time::Duration;
fn main() {
// Spawn a thread
let handle = thread::spawn(|| {
for i in 1..=5 {
println!("spawned: {}", i);
thread::sleep(Duration::from_millis(50));
}
});
// Main thread continues
for i in 1..=3 {
println!("main: {}", i);
thread::sleep(Duration::from_millis(70));
}
handle.join().unwrap(); // Wait for spawned thread to finish
// Move closure: take ownership of captured data
let data = vec![1, 2, 3, 4, 5];
let handle2 = thread::spawn(move || {
// data is moved into this thread
println!("sum: {}", data.iter().sum::());
});
// println!("{:?}", data); // ERROR: data moved into thread
handle2.join().unwrap();
// Spawn multiple threads
let mut handles = vec![];
for i in 0..5 {
let h = thread::spawn(move || {
println!("Thread {} running", i);
i * i // Return value from thread
});
handles.push(h);
}
for h in handles {
let result = h.join().unwrap();
println!("Result: {}", result);
}
} 🎯 Practice
- Spawn 10 threads, each computing the square of their index. Collect all results.
- Write a parallel map: fn pmap<T,U>(data: Vec<T>, f: impl Fn(T)->U+Send+'static) -> Vec<U>
🎉 Key Takeaways
- thread::spawn takes a closure; use move to transfer ownership into the thread
- join() waits for a thread and returns its return value as Result
- The Send trait marks types safe to transfer between threads
- The Sync trait marks types safe to share references between threads