Rust 共享状态并发
Mutex/RwLock 与 Arc 组合实现共享可变状态;锁毒化、粒度与死锁风险。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust 共享状态并发
这个概念为什么出现
有时多线程必须共享可变状态(计数器、缓存)。
Rust 用 Mutex<T>/RwLock<T> 保护数据,用 Arc 共享锁本身。
[!abstract] 一句话理解
Arc<Mutex<T>>让多线程共享同一把锁与数据;只有持有 guard 时才能访问T,把互斥编码进类型。
最小可运行示例
场景:限流计数器——多线程递增通过数
网关工作线程并发递增“已放行请求”计数。
use std::sync::{Arc, Mutex};
use std::thread;
// 业务意图:并发安全递增计数器。
// 教学点:Arc 共享;lock 获取 guard;自动 unlock(Drop)。
fn main() {
let counter = Arc::new(Mutex::new(0u64));
let mut handles = vec![];
for _ in 0..8 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut guard = counter.lock().unwrap();
*guard += 1;
}));
}
for h in handles { h.join().unwrap(); }
println!("allowed={}", *counter.lock().unwrap());
}
建议运行:cargo run
期望输出:
allowed=8
结合场景再看三个关注点
- guard 离开作用域解锁(RAII)
- 锁粒度:只包最小临界区
- poison:持锁 panic 后
lock返回 Err
核心概念与准确模型
| 原语 | 场景 |
|---|---|
Mutex | 独占读写 |
RwLock | 多读或一写 |
Condvar | 等待条件 |
Barrier | 阶段同步 |
lock 返回 LockResult<MutexGuard<T>>。
设计动机
- 数据与锁绑定,避免未加锁访问
- 与 Send/Sync 协作
- Drop 防忘记解锁
边界与误区
- 死锁:锁顺序不一致
- 临界区太大损吞吐
- async 代码误用 std Mutex 长时间持有
[!warning] 常见误区:先 channel 能解决还硬上全局大锁 优先缩小共享面。
工程实践
- 优先消息传递,共享状态次之
- 固定加锁顺序
- 处理 poison 或使用更稳健策略
- 指标监控锁等待
本节总结
- Arc+Mutex 共享可变
- RAII 解锁
- 粒度与死锁是工程问题
自测题
- 为什么需要 Arc 包 Mutex?
- RwLock 读多写少的收益?
参考答案
- Mutex 要共享到多线程需要共享所有权。
- 并发只读不互斥阻塞彼此。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Shared State | 官方书 | Mutex |
| std::sync::Mutex | 标准库 | API |