Guide

Threads

A thread runs code at the same time as the rest of your program. Rust checks at compile time that threads can't break each other's data.

thread::spawn

thread::spawn takes a closure with no arguments and runs it on a new thread. A closure is a small function with no name. || 2 + 3 takes nothing and gives back 5; a longer body goes in braces, like || { ... }. You will learn closures fully in a later section.

spawn returns a JoinHandle right away, not the closure's value, while the new thread keeps working.

use std::thread;let h = thread::spawn(|| 2 + 3);

You can also skip the use line and write std::thread::spawn.

When main ends, the whole program ends, even if other threads are not done.

join

h.join() waits for the thread to finish. It returns a Result: Ok with the closure's value, or Err if the thread panicked.

let n = h.join().unwrap(); // 5

To wait for many threads, keep their handles in a Vec. Vec::new() makes an empty Vec. for _ in 0..3 repeats 3 times; _ means we do not need the number. for h in hs takes each handle out of the Vec in turn.

let mut hs = Vec::new();for _ in 0..3 {    hs.push(thread::spawn(|| 5));}let mut total = 0;for h in hs {    total += h.join().unwrap();}println!("{total}"); // 15

move closures

A spawned thread may live longer than the function that started it. So its closure can't borrow local variables. If it tries, you get error E0373. Add move so the closure owns what it uses:

let v = vec![1, 2, 3];let h = thread::spawn(move || v.len());println!("{}", h.join().unwrap());// v was moved, so main can't use it now

Scoped threads

thread::scope makes threads that must finish before the scope ends. Because of that, they can borrow local data without move.

let v = vec![1, 2, 3];thread::scope(|s| {    s.spawn(|| println!("{}", v.len()));});println!("{:?}", v); // v is still ours

All threads made with s.spawn are joined when thread::scope returns.

Remember

  • spawn starts a thread, join waits for it and gives back its value.
  • E0373 means a spawned closure borrows a local; add move.
  • After move, a non-Copy value belongs to the thread.
  • Use thread::scope when threads only need to borrow.