Content is user-generated and unverified.
use std::thread; use std::sync::{Arc, Mutex, mpsc}; use std::time::Duration; // Example 1: Basic thread spawning fn basic_threads() { println!("=== Basic Threads ==="); // Spawn a new thread let handle = thread::spawn(|| { for i in 1..5 { println!("Thread: count {}", i); thread::sleep(Duration::from_millis(100)); } }); // Main thread continues for i in 1..3 { println!("Main: count {}", i); thread::sleep(Duration::from_millis(100)); } // Wait for the spawned thread to finish handle.join().unwrap(); println!("Thread finished\n"); } // Example 2: Ownership transfer with move fn ownership_transfer() { println!("=== Ownership Transfer ==="); let data = vec![1, 2, 3, 4, 5]; // 'move' keyword transfers ownership to the thread let handle = thread::spawn(move || { println!("Thread owns data now: {:?}", data); data.iter().sum::<i32>() }); // data is no longer accessible here (ownership moved) // println!("{:?}", data); // This would ERROR! let sum = handle.join().unwrap(); println!("Sum calculated in thread: {}\n", sum); } // Example 3: Message passing with channels fn message_passing() { println!("=== Message Passing ==="); // Create a channel: (sender, receiver) let (tx, rx) = mpsc::channel(); thread::spawn(move || { let messages = vec![ "Hello", "from", "the", "thread", ]; for msg in messages { tx.send(msg).unwrap(); thread::sleep(Duration::from_millis(200)); } }); // Receive messages in main thread for received in rx { println!("Received: {}", received); } println!(); } // Example 4: Multiple producers, single consumer fn multiple_producers() { println!("=== Multiple Producers ==="); let (tx, rx) = mpsc::channel(); // Clone sender for multiple threads let tx1 = tx.clone(); let tx2 = tx.clone(); thread::spawn(move || { tx1.send("Message from thread 1").unwrap(); }); thread::spawn(move || { tx2.send("Message from thread 2").unwrap(); }); // Original sender thread::spawn(move || { tx.send("Message from thread 3").unwrap(); }); // Receive all messages for _ in 0..3 { println!("{}", rx.recv().unwrap()); } println!(); } // Example 5: Shared state with Arc and Mutex fn shared_state_mutex() { println!("=== Shared State with Mutex ==="); // Arc = Atomic Reference Counted (shared ownership across threads) // Mutex = Mutual Exclusion (only one thread can access at a time) let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for i in 0..5 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { // Lock the mutex to access the data let mut num = counter.lock().unwrap(); *num += 1; println!("Thread {} incremented counter", i); }); // Lock is automatically released here handles.push(handle); } // Wait for all threads to finish for handle in handles { handle.join().unwrap(); } println!("Final counter value: {}", *counter.lock().unwrap()); println!(); } // Example 6: Preventing data races with ownership fn ownership_prevents_races() { println!("=== Ownership Prevents Data Races ==="); let mut data = vec![1, 2, 3]; // This would NOT compile - can't share mutable reference across threads: // let handle = thread::spawn(|| { // data.push(4); // ERROR: can't capture mutable reference // }); // data.push(5); // ERROR: data already borrowed // Instead, use Arc<Mutex<T>> for shared mutable state let data = Arc::new(Mutex::new(vec![1, 2, 3])); let data_clone = Arc::clone(&data); let handle = thread::spawn(move || { let mut d = data_clone.lock().unwrap(); d.push(4); }); handle.join().unwrap(); println!("Data after thread: {:?}", *data.lock().unwrap()); println!(); } // Example 7: Deadlock prevention with lock ordering fn deadlock_example() { println!("=== Deadlock Prevention ==="); let resource1 = Arc::new(Mutex::new(0)); let resource2 = Arc::new(Mutex::new(0)); // Good practice: always lock in the same order let r1 = Arc::clone(&resource1); let r2 = Arc::clone(&resource2); let handle1 = thread::spawn(move || { let _lock1 = r1.lock().unwrap(); println!("Thread 1: locked resource 1"); thread::sleep(Duration::from_millis(50)); let _lock2 = r2.lock().unwrap(); println!("Thread 1: locked resource 2"); }); let r1 = Arc::clone(&resource1); let r2 = Arc::clone(&resource2); let handle2 = thread::spawn(move || { // Lock in SAME order as thread 1 (prevents deadlock) let _lock1 = r1.lock().unwrap(); println!("Thread 2: locked resource 1"); thread::sleep(Duration::from_millis(50)); let _lock2 = r2.lock().unwrap(); println!("Thread 2: locked resource 2"); }); handle1.join().unwrap(); handle2.join().unwrap(); println!(); } // Example 8: Send and Sync traits fn send_sync_traits() { println!("=== Send and Sync Traits ==="); // Send: type can transfer ownership between threads // Sync: type can be referenced from multiple threads // Most types are Send and Sync let data = vec![1, 2, 3]; // Vec is Send and Sync thread::spawn(move || { println!("Vec is Send, ownership transferred: {:?}", data); }).join().unwrap(); // Arc allows sharing across threads (Sync) let shared_data = Arc::new(vec![1, 2, 3]); let shared_clone = Arc::clone(&shared_data); thread::spawn(move || { println!("Arc is Sync, shared reference: {:?}", shared_clone); }).join().unwrap(); println!("Original still accessible: {:?}", shared_data); println!(); } // Example 9: Scoped threads (no need for 'static lifetime) fn scoped_threads() { println!("=== Scoped Threads ==="); let mut data = vec![1, 2, 3]; thread::scope(|s| { // Can borrow non-'static data safely s.spawn(|| { println!("Scoped thread can read: {:?}", data); }); s.spawn(|| { println!("Another scoped thread: {:?}", data); }); // All scoped threads complete before scope ends }); // data is still accessible data.push(4); println!("After scoped threads: {:?}", data); println!(); } // Example 10: Parallel iteration with rayon // Note: This example shows the concept, but rayon isn't in std fn parallel_computation_concept() { println!("=== Parallel Computation Concept ==="); let numbers: Vec<i32> = (0..100).collect(); // Sequential let sum: i32 = numbers.iter().map(|x| x * 2).sum(); println!("Sequential sum: {}", sum); // With rayon (external crate), you could do: // let sum: i32 = numbers.par_iter().map(|x| x * 2).sum(); // This automatically uses multiple threads! println!(); } fn main() { basic_threads(); ownership_transfer(); message_passing(); multiple_producers(); shared_state_mutex(); ownership_prevents_races(); deadlock_example(); send_sync_traits(); scoped_threads(); parallel_computation_concept(); println!("=== Key Takeaways ==="); println!("1. Ownership prevents data races at compile time"); println!("2. Use channels (mpsc) for message passing"); println!("3. Use Arc<Mutex<T>> for shared mutable state"); println!("4. Send trait: ownership can transfer between threads"); println!("5. Sync trait: safe to reference from multiple threads"); println!("6. Compiler enforces thread safety!"); }
Content is user-generated and unverified.
    Rust Concurrency Guide: 10 Threading & Parallelism Examples | Claude