22.6 Channels for Message Passing
Besides shared-memory concurrency, Rust offers message passing, where threads exchange data by transferring ownership rather than sharing mutable state. This can prevent certain classes of concurrency bugs.
22.6.1 Basic Usage with std::sync::mpsc
Rust’s standard library provides an asynchronous MPSC (multiple-producer, single-consumer) channel:
use std::sync::mpsc; use std::thread; use std::time::Duration; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { for i in 0..5 { tx.send(i).unwrap(); thread::sleep(Duration::from_millis(50)); } }); for received in rx { println!("Got: {}", received); } }
When all senders are dropped, the channel closes, and the receiver’s iterator terminates.
22.6.2 Multiple Senders
Clone the transmitter to allow multiple threads to send messages:
use std::sync::mpsc; use std::thread; fn main() { let (tx, rx) = mpsc::channel(); let tx1 = tx.clone(); thread::spawn(move || { tx1.send("Hi from tx1").unwrap(); }); thread::spawn(move || { tx.send("Hi from tx").unwrap(); }); for msg in rx { println!("Received: {}", msg); } }
By default, there’s one receiver. For multiple consumers or more advanced patterns, consider crates like Crossbeam or kanal.
22.6.3 Blocking and Non-Blocking Receives
recv()
blocks until a message arrives or the channel closes.try_recv()
checks immediately, returning an error if there’s no data or the channel is closed.
use std::sync::mpsc::{self, TryRecvError}; use std::thread; use std::time::Duration; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { for i in 0..3 { tx.send(i).unwrap(); thread::sleep(Duration::from_millis(50)); } }); loop { match rx.try_recv() { Ok(value) => println!("Got: {}", value), Err(TryRecvError::Empty) => { println!("No data yet..."); } Err(TryRecvError::Disconnected) => { println!("Channel closed"); break; } } thread::sleep(Duration::from_millis(20)); } }
22.6.4 Bidirectional Communication
Standard channels are one-way (MPSC). For request–response patterns, you can create two channels—one for each direction—so each thread has a sender and a receiver. For multiple receivers, external crates such as Crossbeam provide MPMC (multi-producer, multi-consumer) channels.