Rust Fearless Concurrency
Concurrency means a program makes progress on several jobs at once, instead of one job after another. Rust calls its approach fearless concurrency, because mistakes other languages find at run time are refused while the code is still being written.
spawn starts a second thread
A process is one running program. Threads are the independent parts inside it. They can run at the same time. Rust threads are 1:1 — one language thread is one operating-system thread:
let handle = thread::spawn(|| 40 + 2);
// a second thread now runs the closure; main carries onjoin waits, and collects the answer
let answer = handle.join().unwrap();
println!("answer from thread = {}", answer); // answer from thread = 42A race condition: the answer depends on the order
Threads reach shared data in an order nobody planned, and the answer depends on the order:
// two threads update one counter, with no plan for who goes first:
counter += 1; // thread A reads 5 and plans to write 6
counter += 1; // thread B also reads 5 and also writes 6
// two updates happened, yet the counter ends at 6: one update was lostA deadlock: each thread waits for the other
// thread A holds the first lock and waits for the second;
// thread B holds the second lock and waits for the first.
// Neither can ever continue: that frozen circle is a deadlock.Two tool families — Rust dictates neither
You will meet both in this section. Pick per problem:
// pass messages over a channel:
tx.send(value); // the value travels to the receiver
// or share state behind a lock:
let shared = Arc::new(Mutex::new(value));Example
use std::thread;
fn main() {
let handle = thread::spawn(|| 40 + 2);
let answer = handle.join().unwrap();
println!("answer from thread = {}", answer);
}Key points
- Concurrent: several jobs make progress by taking turns, even on one processor core
- Parallel: several jobs truly run at the same moment, on different cores
- Fearless: Rust checks thread code with the same ownership and type rules as all code.
- So many concurrency bugs become compile errors.
- They do not stay rare run-time crashes.
- The safety rules in this section guard both.
- Concurrency is famously easy to get wrong.
In this example, thread::spawn starts a second thread that adds 40 + 2. The closure gives back 42, and spawn hands main a handle. handle.join() waits for the thread to finish and returns its value inside Ok, so unwrap() takes the 42 out. The println! then prints answer from thread = 42. Two parts of the program ran as separate threads. The handover was checked by the compiler. That is the fearless idea in miniature.
Note
In Rust writing, the word concurrent often covers both concurrent and parallel work.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does fearless concurrency mean in practice?