2. 线程间消息传递
任务说明
本案例要求使用 Rust 标准库中的 std::sync::mpsc::channel 实现多线程间的消息传递。具体目标为:创建两个工作线程,主线程通过通道向它们发送任务消息,工作线程接收并处理消息后,通过另一个通道将结果返回给主线程。通过该案例掌握 mpsc 通道的创建、发送(Sender)、接收(Receiver)以及多生产者单消费者的基本用法。
核心实现
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;
use std::time::Duration;
/// 工作线程:接收数值消息,计算平方后通过结果通道返回
fn worker(id: u32, rx: Receiver<i32>, result_tx: Sender<(u32, i32)>) {
for num in rx {
let squared = num * num;
// 模拟耗时计算
thread::sleep(Duration::from_millis(10));
result_tx.send((id, squared)).expect("发送结果失败");
}
}
fn main() {
// 任务通道:主线程 -> 工作线程
let (task_tx, task_rx) = channel::<i32>();
// 结果通道:工作线程 -> 主线程
let (result_tx, result_rx) = channel::<(u32, i32)>();
// 创建两个工作线程,每个线程持有 task_rx 的一个接收端
// 注意:Receiver 不能被克隆,因此使用 Arc<Mutex<Receiver>> 共享
let rx = std::sync::Arc::new(std::sync::Mutex::new(task_rx));
let mut handles = Vec::new();
for id in 0..2 {
let rx = std::sync::Arc::clone(&rx);
let result_tx = result_tx.clone();
handles.push(thread::spawn(move || {
// 从共享接收端获取独占锁,再调用 recv 接收消息
let rx_guard = rx.lock().unwrap();
worker(id, rx_guard);
}));
}
// 主线程发送 5 个任务
for i in 1..=5 {
task_tx.send(i).expect("发送任务失败");
}
// 丢弃发送端,使工作线程的 recv 在消息耗尽后返回 Err 并退出循环
drop(task_tx);
// 接收所有工作线程的结果(共 5 个)
let mut results = Vec::new();
for _ in 0..5 {
if let Ok((id, val)) = result_rx.recv() {
results.push((id, val));
}
}
// 等待工作线程结束
for h in handles {
h.join().unwrap();
}
// 输出结果(按接收顺序)
for (id, val) in &results {
println!("Worker {} 返回: {}", id, val);
}
}
关键说明
std::sync::mpsc::channel 创建的是多生产者单消费者通道,Sender 可克隆以支持多线程发送,而 Receiver 不可克隆。本案例中两个工作线程需要共享同一个 Receiver,因此使用 Arc<Mutex<Receiver>> 包装,每次接收前获取互斥锁,保证同一时刻只有一个线程从通道取消息。主线程发送完所有任务后主动 drop(task_tx),使通道关闭,工作线程的 for num in rx 循环在消息耗尽后自动终止。
编译与运行
# 保存为 main.rs,然后执行:
rustc main.rs
./main
验证方法
程序运行后,主线程会依次打印 5 行输出,每行格式为 Worker {id} 返回: {平方值}。其中 id 为 0 或 1(表示处理该任务的工作线程编号),平方值应为对应输入数字的平方。由于两个工作线程并发消费任务,输出顺序可能交错,但 5 个结果必须完整出现且数值正确(1、4、9、16、25 的平方对应 1、4、9、16、25)。若程序正常退出且无 panic,且打印结果包含全部 5 个平方值,则判定案例通过。