std::sync::mpsc Channel
For inter-thread communication in Rust, use the std::sync::mpsc (multiple producer, single consumer) channel. This is a message-passing pattern where you send values from the sender (Sender) side and receive them on the receiver (Receiver) side.
Syntax
use std::sync::mpsc;
use std::thread;
// Create a channel (tx: sender, rx: receiver).
let (tx, rx) = mpsc::channel();
// Send a value (tx can be cloned, so multiple threads can send).
tx.send(value).unwrap();
// Receive a value (blocks until the next message arrives).
let received = rx.recv().unwrap();
// Non-blocking receive (returns Err immediately if no message is available).
match rx.try_recv() {
Ok(val) => println!("{}", val),
Err(_) => println!("No message yet"),
}
// Receive all messages (loop ends when all senders are dropped).
for msg in rx {
println!("{}", msg);
}
Method List
| Method | Description |
|---|---|
| mpsc::channel() | Creates an asynchronous channel. Returns (Sender<T>, Receiver<T>). |
| mpsc::sync_channel(n) | Creates a synchronous channel with a buffer capacity of n. Blocks on send when the buffer is full. |
| tx.send(val) | Sends a value. Returns Err if the receiver has been dropped. |
| tx.clone() | Clones the sender, allowing multiple threads to send on the same channel. |
| rx.recv() | Blocks until a value is received. Returns Err when all senders have been dropped. |
| rx.try_recv() | Attempts to receive immediately. Returns Err right away if no message is available (non-blocking). |
| rx.recv_timeout(dur) | Receives with a timeout. |
| for msg in rx | Iterates over received messages until all senders are closed. |
Sample Code
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
// --- Basic send and receive ---
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(String::from("Hello from the thread!")).unwrap();
});
let msg = rx.recv().unwrap();
println!("Received: {}", msg);
// --- Sending and receiving multiple messages ---
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let messages = vec!["ping", "pong", "done"];
for msg in messages {
tx.send(msg).unwrap();
thread::sleep(Duration::from_millis(10));
}
// When tx is dropped, iteration on rx ends.
});
for msg in rx {
println!("Received: {}", msg);
}
// --- Multiple producers (the "multiple producer" in mpsc) ---
let (tx, rx) = mpsc::channel();
let mut handles = vec![];
for i in 0..3 {
let tx_clone = tx.clone(); // Clone the sender.
let h = thread::spawn(move || {
tx_clone.send(format!("Sender {}: data", i)).unwrap();
});
handles.push(h);
}
drop(tx); // Close the original tx (so the rx iteration can end).
for msg in rx {
println!("{}", msg);
}
for h in handles {
h.join().unwrap();
}
// --- Non-blocking receive with try_recv ---
let (tx, rx) = mpsc::channel::<i32>();
thread::spawn(move || {
thread::sleep(Duration::from_millis(50));
tx.send(42).unwrap();
});
loop {
match rx.try_recv() {
Ok(val) => { println!("Received: {}", val); break; }
Err(mpsc::TryRecvError::Empty) => {
println!("Not yet...");
thread::sleep(Duration::from_millis(20));
}
Err(mpsc::TryRecvError::Disconnected) => break,
}
}
}
Overview
mpsc::channel() creates a "multiple producer, single consumer" channel. The sender (Sender) can be cloned with clone(), allowing multiple threads to send, but the receiver (Receiver) cannot be cloned (single consumer).
When all Senders are dropped, rx.recv() returns Err and any for msg in rx loop ends. You can use this behavior to detect when worker threads have finished.
For inter-thread communication via shared memory, see Mutex<T> / RwLock<T>. For creating and waiting on threads, see std::thread::spawn() / join().
If you find any errors or copyright issues, please contact us.