Message passing
If we want our code to be a bit more ergonomic, we can use message passing instead of shared memory. Conceptually, we have a pipe where we can use one thread to push data in, and then another thread to get the data out again on the other end.
The state of this pipe is abstracted away by the Rust standard library's Sender
or SyncSender
and Receiver
.
The "pipe" can buffer data if desired, so some amount of decoupling can be achieved. Otherwise, the access is blocking by default, so a thread will wait on the receiving end until a value comes through.
When one end of the pipe gets closed, the other end receives a signal, enabling appropriate handling.
#![allow(unused)] fn main() { let (task_sender, task_receiver) = std::sync::mpsc::channel(); let (result_sender, result_receiver) = std::sync::mpsc::channel(); let thread = std::thread::spawn(move || { let mut sum: usize = 0; // Receive until pipe disconnects while let Ok(number) = task_receiver.recv() { sum += number; result_sender.send(sum).unwrap(); } }); for i in 0..20 { task_sender.send(i).unwrap(); } // Signal to the other thread that there will be no more tasks std::mem::drop(task_sender); while let Ok(sum) = result_receiver.recv() { println!("Result: {}", sum); } // Thread should be finished thread.join().unwrap(); }