Rust's standard library thread feature allows using operating system threads in a one to one manner. It's not often the best option for concurrent programming.
main thread termination
use std::{thread, time::Duration};
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread");
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {i} from the main thread");
thread::sleep(Duration::from_millis(1));
}
}
When the main thread completes all spawned threads are shutdown so the output of the above function will likely be a little different each time you run it:
hi number 1 from the main thread
hi number 1 from the spawned thread
hi number 2 from the main thread
hi number 2 from the spawned thread
hi number 3 from the main thread
hi number 3 from the spawned thread
hi number 4 from the main thread
hi number 4 from the spawned thread
hi number %
wait for threads to finish
The return type of thread::spawn is JoinHandle<T> which is an owned value
that has a join method which blocks until its thread finishes.
use std::{thread, time::Duration};
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread");
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {i} from the main thread");
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
move values into threads
Rust forces us to move values, like v into the closure creating our threads if
we wish to use them. This ensures the value will not be dropped or otherwise
messed with while we're doing work in our thread.
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {v:?}");
});
drop(v); // Compile error! Use of moved value.
handle.join().unwrap();
}