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 个平方值,则判定案例通过。

主线程 发送任务/收集结果 task_tx (Sender) Arc<Mutex<Receiver>> Worker 0 计算平方 Worker 1 计算平方 result_tx (Sender) result_rx (Receiver) send recv recv send send recv 结果 任务通道:主线程 → 工作线程(多生产者单消费者,Receiver 共享加锁) 结果通道:工作线程 → 主线程(每个 Worker 持有克隆的 Sender)