// Copyright 2026 Amber Hu
use std::thread;
use std::sync::Mutex;

fn main() {
    let mut handlers = Vec::new();
    for name in 'a'..'e' {
        println!("Spawning thread {name}");
        
        // Anonymous function syntax
        let handler = thread::spawn(move || {
            for i in 0..5 {
                println!("Thread {name} Iteration {i}");
            }
        });
        handlers.push(handler);
    }
    for handler in handlers {
        handler.join().unwrap();
    }
    
    // Now let's synchronize mutable data across threads using Mutex
    let counter = Mutex::new(0);
    println!("Original data value: {:?}", counter.lock().unwrap());
    incr_scoped(4, 100, &counter);
    println!("Final data value: {:?}", counter.lock().unwrap());
}

fn incr_scoped(threads: u32, iters : u32, data : &Mutex<i32>) {
    // thread::scope does the joining for us, and lets us borrow `data` by ref
    thread::scope(|s| {
        for _ in 0..4 {
            s.spawn(|| {
                for _ in 0..100 {
                    let mut mutex_guard = data.lock().unwrap();
                    *mutex_guard += 1;
                    // Don't need to unlock, because it automatically
                    // unlocks after mutex_guard goes out of scope!
                }
            });
        }
        // All threads are automatically joined here
    });
}