Concurrency: The "Fearless Threads"
In modern JavaScript, you use Promises (async/await) or Web Workers for “concurrency.” In Rust, you have OS-level threads (std::thread). These are much more powerful but also more dangerous in other languages.
In Rust, this is called “Fearless Concurrency.” Why “Fearless”? Because the Ownership Contract ensures that it’s impossible for two threads to fight over the same data at the same time. If your code compiles, it’s safe from the most common threading crashes.
🏗️ The 3-Step Narrative
1. Spawning (The “Web Worker”)
Just like a Web Worker runs a separate script, thread::spawn creates a new execution path.
use std::thread;use std::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)); } });
handle.join().unwrap(); // ⏳ This "Waits" for the worker to finish!}2. Sharing (The “Arc Mutex” Container)
If multiple threads need to own and change the same data, you need the Arc<Mutex<T>> container.
- Arc: Atomic Reference Counting (The thread-safe version of
Rc). - Mutex: Mutual Exclusion (Ensures only one thread can touch the data at a time).
use std::sync::{Arc, Mutex};let counter = Arc::new(Mutex::new(0));
thread::spawn(move || { let mut num = counter.lock().unwrap(); // 🔐 Locking for safe access *num += 1; // Mutate safely!}); // 🔓 Lock is automatically released here3. Messaging (The “Channel”)
Instead of sharing memory, Rust programmers often say: “Communicate by sharing, don’t share by communicating.” You send data through a “pipe” (a Channel).
use std::sync::mpsc; // Multiple Producer, Single Consumer
let (tx, rx) = mpsc::channel(); // Transmitter & Receiver
thread::spawn(move || { tx.send("hi").unwrap(); // 📤 Sending a message});
let message = rx.recv().unwrap(); // 📥 Blocks until it arrivesNOTE: Parity with JS
This is exactly like
worker.postMessage()andwindow.onmessage.
🔬 From the Official Book
🛡️ The Send & Sync Traits
Every type in Rust decides if it’s safe to share across threads by “signing” these traits:
- Send: “I can be moved to another thread.”
- Sync: “I can be accessed from multiple threads at once.”
Most types sign these automatically. If you try to send a non-safe type (like Rc), the compiler will refuse to run your code.
💡 What Concurrency Unlocks
- Real-Time Parallelism: Use every core on your CPU without worrying about “Data Races.”
- Reliable Backend Logic: Build high-performance servers that handle millions of requests without the overhead of a garbage collector.
- Fearless Async: When you move to
async/await(using a crate liketokio), you have the same safety guarantees as regular threads. - No More Rare Crashes: Threading bugs in C++ are notorious for being “Heisenbugs” (hard to find). In Rust, they are caught before you even run the code.