A thread is a second line of execution inside the same process. In Rust you start one with std::thread::spawn, which takes a closure and immediately returns a JoinHandle. The closure starts running right away, in parallel with the code that spawned it.
The handle is the only way back. Calling join() on it blocks the current thread until the spawned one finishes, and hands you whatever the closure returned. That return value is how work crosses the thread boundary: no channels, no shared memory, just a value coming back out of join().
Because the closure may outlive the function that created it, spawn requires the closure to own everything it touches. That is what the move keyword is for, and it is why values below is moved into the thread rather than borrowed.
Implement two functions.
sum_in_threadpub fn sum_in_thread(values: Vec<u64>) -> u64Spawn a thread that adds up values, join it, and return the total.
assert_eq!(sum_in_thread(vec![1, 2, 3]), 6);
assert_eq!(sum_in_thread(vec![]), 0);spawn_counterpub fn spawn_counter(
start: u64,
steps: u64,
) -> JoinHandle<u64>Spawn a thread that adds up steps consecutive numbers beginning at start, and return the handle without joining it. The caller decides when to block.
// 10 + 11 + 12
let h = spawn_counter(10, 3);
assert_eq!(h.join().unwrap(), 33);
// no steps means nothing to add
assert_eq!(spawn_counter(7, 0).join().unwrap(), 0);join() returns a Result. Panics inside a thread are a topic of their own, so unwrap() is fine here.thread::spawn(move || { ... }) returns a JoinHandle<T>, where T is the closure's return type.(0..steps).map(|i| start + i).sum() avoids a manual loop.move.A thread is a second line of execution inside the same process. In Rust you start one with std::thread::spawn, which takes a closure and immediately returns a JoinHandle. The closure starts running right away, in parallel with the code that spawned it.
The handle is the only way back. Calling join() on it blocks the current thread until the spawned one finishes, and hands you whatever the closure returned. That return value is how work crosses the thread boundary: no channels, no shared memory, just a value coming back out of join().
Because the closure may outlive the function that created it, spawn requires the closure to own everything it touches. That is what the move keyword is for, and it is why values below is moved into the thread rather than borrowed.
Implement two functions.
sum_in_threadpub fn sum_in_thread(values: Vec<u64>) -> u64Spawn a thread that adds up values, join it, and return the total.
assert_eq!(sum_in_thread(vec![1, 2, 3]), 6);
assert_eq!(sum_in_thread(vec![]), 0);spawn_counterpub fn spawn_counter(
start: u64,
steps: u64,
) -> JoinHandle<u64>Spawn a thread that adds up steps consecutive numbers beginning at start, and return the handle without joining it. The caller decides when to block.
// 10 + 11 + 12
let h = spawn_counter(10, 3);
assert_eq!(h.join().unwrap(), 33);
// no steps means nothing to add
assert_eq!(spawn_counter(7, 0).join().unwrap(), 0);join() returns a Result. Panics inside a thread are a topic of their own, so unwrap() is fine here.thread::spawn(move || { ... }) returns a JoinHandle<T>, where T is the closure's return type.(0..steps).map(|i| start + i).sum() avoids a manual loop.move.