16-无畏并发

线程、信道、Mutex/Arc 与 Send/Sync 并发精要

精要笔记 · 基于 TRPL 简体中文 第16章

无畏并发

Rust 用所有权 + 类型系统在编译时捕获并发错误 → 无畏并发(fearless concurrency)。

并发 = 独立执行;并行 = 同时执行。本章聚焦并发。

使用线程同时运行代码

  • Rust 标准库用 1:1 线程模型(每个语言线程 = 一个 OS 线程)。

使用 spawn 创建新线程

1
2
3
4
thread::spawn(|| {
    for i in 1..10 { println!("hi {i} from spawned"); }
});
// 主线程结束 → 所有 spawn 线程也结束

等待所有线程结束

1
2
let handle = thread::spawn(|| { /* ... */ });
handle.join().unwrap();  // 阻塞直到线程结束
  • join() 位置影响执行顺序:放在循环前 → 子线程先跑完。

将 move 闭包与线程一同使用

  • 传给 thread::spawn 的闭包常用 move — 取得环境值所有权,避免悬垂引用。
1
2
3
4
5
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
    println!("{:?}", v);
});
// v 已被 move 进闭包,主线程不能再使用

使用消息传递在线程间传送数据

“不要通过共享内存来通讯;而要通过通讯来共享内存。”

基本用法

1
2
3
4
5
6
7
8
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();

thread::spawn(move || {
    tx.send(String::from("hi")).unwrap();
});

let received = rx.recv().unwrap();  // 阻塞等待
  • mpsc = 多生产者,单消费者。
  • tx.clone() 创建额外发送端。
  • send 移动所有权 → 发送后不能再使用值。
  • rx 当迭代器:for msg in rx { ... } — 信道关闭时结束。
  • try_recv() — 非阻塞,立即返回 Result。

共享状态并发

使用互斥器控制访问

1
2
3
4
5
let m = Mutex::new(5);
{
    let mut num = m.lock().unwrap();  // 获取锁
    *num = 6;
}  // MutexGuard drop → 自动解锁
  • Mutex<T> 是智能指针;lock() 返回 MutexGuard(实现 Deref + Drop)。
  • 规则:先 lock,用完自动 unlock。

给 Mutex<T> 共享访问

  • 多线程共享 Mutex → 需要 Arc<T>(原子引用计数,线程安全版 Rc)。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
    let counter = Arc::clone(&counter);
    handles.push(thread::spawn(move || {
        let mut num = counter.lock().unwrap();
        *num += 1;
    }));
}
// 结果: 10
  • Rc<T> 不能跨线程(未实现 Send)→ 编译错误。
  • Arc<T> + Mutex<T> = 多线程共享可变数据。
  • 简单数值运算可用 AtomicI32 等(std::sync::atomic),比 Mutex 更高效。

比较 RefCell<T>/Rc<T> 和 Mutex<T>/Arc<T>

单线程多线程
RefCell<T> / Rc<T>Mutex<T> / Arc<T>
  • Mutex 提供内部可变性;Arc<Mutex<T>> 类似 Rc<RefCell<T>> 但线程安全。
  • 注意死锁风险(两个线程各持一把锁互相等待)。

使用 Send 和 Sync trait 的可扩展并发

在线程间转移所有权 — Send

  • Send:类型所有权可在线程间传送。
  • 几乎所有类型都是 Send;例外:Rc<T>(非线程安全引用计数)。

多线程访问 — Sync

  • Sync:&T 可安全地在多线程间共享(即 &T 实现了 Send)。
  • 例外:Rc<T>、RefCell<T>、Cell<T> 未实现 Sync。
  • Mutex<T> 实现了 Sync。

手动实现 Send 和 Sync 是不安全的

  • 标记 trait,无方法。组合类型自动实现。
  • 手动实现需 unsafe Rust。

总结

机制用途
thread::spawn + move创建线程
mpsc::channel消息传递(所有权转移)
Arc<Mutex<T>>共享可变状态
Send / Sync编译时并发安全检查

更多并发方案见社区 crate。下一章:async/await。

最后修改 July 30, 2026: 更新 (33710aaae)