← [ BACK_TO_NOTES ]

Rust 共享状态并发

Mutex/RwLock 与 Arc 组合实现共享可变状态;锁毒化、粒度与死锁风险。

#concept #growing #dev #rust

[!info] related notes

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

结合场景再看三个关注点

  1. guard 离开作用域解锁(RAII)
  2. 锁粒度:只包最小临界区
  3. std 锁的 poison 是建议性信号:持有 Mutex 时发生 panic 通常会标记毒化;它不保证捕获所有不变量破坏

核心概念与准确模型

原语场景
Mutex独占读写
RwLock多读或一写
Condvar等待条件
Barrier阶段同步

lock 返回 LockResult<MutexGuard<T>>。

设计动机

  • 数据与锁绑定,避免未加锁访问
  • 与 Send/Sync 协作
  • Drop 防忘记解锁

边界与误区

  • 死锁:锁顺序不一致
  • 临界区太大损吞吐
  • poison 后是否恢复需检查/修复数据不变量;into_inner 只是取出 guard,不自动修复数据。std RwLock 通常仅写锁期间的 panic 导致 poison
  • async 中可以用 std Mutex 保护短小、无 await 的低争用临界区;持锁等待 I/O 或跨 await 易阻塞执行器或死锁,需要时选 async 锁并控制临界区
  • Mutex 不保证重入,同线程重复加锁也可能死锁;RwLock 的调度与写者优先级不保证跨平台一致

[!warning] 常见误区:先 channel 能解决还硬上全局大锁 优先缩小共享面。

工程实践

  1. 优先消息传递,共享状态次之
  2. 固定加锁顺序
  3. 处理 poison 或使用更稳健策略
  4. 指标监控锁等待

本节总结

  • Arc+Mutex 共享可变
  • RAII 解锁
  • 粒度与死锁是工程问题

自测题

  1. 为什么需要 Arc 包 Mutex?
  2. RwLock 读多写少的收益?
参考答案
  1. 示例中的线程需要共同持有锁,因此用 Arc;作用域线程也可借用同一 Mutex,不是所有共享锁都必须包 Arc。
  2. 允许多个读 guard 并存;实际收益取决于锁成本、争用与写者调度,读多不保证一定更快。

延伸阅读与资料来源

资料类型支撑内容
The Book — Shared State官方书Mutex
std::sync::Mutex标准库API
创建于 2026/7/15 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本