Challenge 2: Five Threads Pushing to a Shared Vec — Possible Solution ==================================================================== use std::sync::{Arc, Mutex}; use std::thread; fn main() { let shared = Arc::new(Mutex::new(Vec::new())); let mut handles = vec![]; for i in 0..5 { let shared = Arc::clone(&shared); handles.push(thread::spawn(move || { let mut vec = shared.lock().unwrap(); vec.push(i); })); } for h in handles { h.join().unwrap(); } let final_vec = shared.lock().unwrap(); println!("Length: {}", final_vec.len()); // 5 assert_eq!(final_vec.len(), 5); } WHY THIS WORKS AS AN ANSWER ------------------------------ Arc::clone(&shared) is called ONCE PER LOOP ITERATION, inside the loop, producing five separate Arc handles all pointing at the SAME underlying Mutex> — exactly this chapter's counter example pattern, generalized from incrementing a number to pushing onto a vector. Each spawned thread's move closure takes ownership of ITS OWN cloned shared handle (not the original), and calls shared.lock().unwrap() to obtain exclusive, safe access before pushing its own loop index i — the Mutex guarantees no two threads can push simultaneously and corrupt the vector's internal state, which is precisely the data-race protection this chapter's Arc> section described. Joining all five handles BEFORE reading the final vector is essential — without it, main might read final_vec before every thread has finished its push, non-deterministically seeing anywhere from 0 to 5 items depending on timing. Only after every handle.join() has completed can main safely assume all five pushes have already happened, which is exactly why the final length is guaranteed to be 5 every time this program runs, not just usually.