In Rust, creating and using threads can be achieved through the std::thread module in the standard library. Rust's threading model allows creating true threads at the operating system level (i.e., OS threads), unlike some other languages that employ green threads or lightweight threads.
Creating Threads
To create a new thread in Rust, the std::thread::spawn function is typically used. This function takes a closure containing the code that the thread will execute. For example:
rustuse std::thread; fn main() { let new_thread = thread::spawn(|| { // This is the code the new thread will execute for i in 1..10 { println!("New thread: {}", i); thread::sleep(std::time::Duration::from_millis(1)); } }); for i in 1..10 { println!("Main thread: {}", i); thread::sleep(std::time::Duration::from_millis(1)); } // Wait for the newly created thread to complete new_thread.join().unwrap(); }
Waiting for Threads to Complete with join
In the above example, we used the join() method. This method blocks the current thread until the thread it is called on finishes. If the thread completes successfully, join() returns a Result; otherwise, it returns an error.
Thread Data Sharing
Rust's ownership and borrowing rules remain applicable in multi-threaded contexts, helping to prevent data races. To share data across threads, you can use atomic types, mutexes (Mutex), or share ownership using Arc (atomic reference counting).
For example, using Arc and Mutex to share mutable data:
rustuse std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); }
In this example, counter is a shared variable protected by a Mutex, wrapped in an Arc to enable safe sharing of ownership among multiple threads. Each thread modifies the shared variable by incrementing the count. Locking the Mutex ensures that only one thread accesses the data at a time, preventing data races.
Conclusion
In Rust, creating and managing threads is both safe and straightforward. Rust's memory safety guarantees and type system provide robust tools for developers to write multi-threaded programs free of data races.