第8章 并发审判庭


第 8 章 · 并发审判庭

本章要回答的三个问题:开线程时数据的产权怎么移交?线程间通信选消息传递还是共享内存?Send 与 Sync 两条标记契约凭什么把数据竞争挡在编译期?

为什么要有这一章

第 1 章卷宗三(数据竞争)在这里终审。多数语言靠运行时锁检查或纯粹靠程序员自觉,Rust 的判法还是老一套:把权限写进类型。线程闭包要拿数据所有权,跨线程共享要先过 Send 与 Sync 的资格审查,锁的守卫生命周期与借用规则绑定——忘了解锁不是 bug,是编译错误。

读完能解决什么

  • 用 spawn 与 join 开收线程,理解闭包的 move 语义;
  • 按场景选 channel 或 Mutex,写出无竞争代码;
  • 解释 Arc 与 Rc、Mutex 与 RefCell 的两两对应关系。

各节怎么分工

节 回答哪个问题 关键产出
8.1 线程 产权怎么进线程 move 闭包、join 等待
8.2 消息传递 所有权流转式通信 mpsc 通道、clone 共享发送端
8.3 共享状态 共享加锁怎么写 Mutex、Arc、Send 与 Sync

先决条件

  • 第 3 章所有权与借用、第 5 章 Trait 标记的思想。

往下走到哪

第 11 章异步编程是并发的另一条路线:少量线程跑海量任务,与本章的 OS 线程路线互补。

本章判例速查

报错 案情 修法方向
E0373 闭包借用环境去 spawn 加 move 捕获
E0277 非 Send 类型跨线程 Rc→Arc、RefCell→Mutex
E0382 move 后原变量使用 clone 或 Arc 共享
挂起无报错 死锁 锁全序、缩小临界区

两条路线的选型卡

维度 消息传递 共享状态
产权 随消息移交 锁内借用
适合 流水线、任务分发 计数器、缓存、配置
陷阱 无界通道内存涨 死锁、锁粒度过大
心智负担 所有权自然分割 需要额外纪律

Go 阵营"不要靠共享内存来通信"的口号在 Rust 里被编译器执行成法条:两条路线都安全,选型看数据流向而非口味。单向流动优先通道,多点读写同一状态才上锁。

与下一章的衔接

并发代码高度重复的模式——起 N 个 worker、注册一堆处理器、生成样板测试——正是宏的主场。第 9 章的声明宏会直接把本章 worker 池的样板宏化,作为学以致用的判例。

并发自查清单

并发代码提交前过一遍:每个 spawn 的闭包捕获方式(move 与否)是否经过选择而非顺手;每个 join 的 Err 分支是否有处理;锁的获取顺序是否遵守全局全序;通道是否有界或已论证无需界;共享可变数据是否全部经过 Arc 包装而无一裸奔。五问全过,数据竞争在编译期与设计期就已被双重拦截——这正是 Rust 并发的承诺:安全靠编译器,正确靠纪律。

三道自测题

一问:为什么 Rc 不能跨线程而 Arc 可以?答:Rc 计数非原子,并发更新会算错并双重释放;Arc 用原子计数。二问:死锁的鉴别特征是什么?答:线程挂起、CPU 空闲、无 panic 无报错。三问:无界 channel 的风险?答:生产快于消费时内存无上限增长,需换 sync_channel 定容。三题过关,并发庭的两大路线——传递与共享——就已把各自的坑位地图画全。

结案要旨

并发庭三节合起来是一份风险清单:起线程审捕获方式(第 8.1 节)、传消息审通道容量与关闭(第 8.2 节)、共状态审锁序与中毒(第 8.3 节)。三份清单之外再记一条总则:并发 bug 的复现概率与线程数成反比,能在两线程、加断言、固定节奏的测试里复现的问题不要留到生产环境碰运气。Rust 把数据竞争挡在编译期,逻辑层面的死锁与饥饿仍属设计与测试的辖区——这份分工认识本身,就是并发章最重要的产出。

作者与出处
原作者:灏天文库
来源:平台策划编纂
整理人: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U