跳转至

第3章 并发、同步与死锁

并发让系统在等待 I/O 时继续做别的工作,也让多核 CPU 真正同时执行多个任务。但只要多个执行流共享可变状态,程序结果就可能依赖难以复现的执行时序。

从“交错”理解并发

两个线程各自的代码顺序没有变化,但它们的指令可以按许多方式交错。正确的并发程序必须保证:在所有允许的交错中,关键不变量都成立。

最小例子是两个线程同时执行 counter++。这通常包含读取、加一和写回三个步骤;如果两者都读到旧值,最终只增加一次。问题不在算术,而在复合操作缺少原子性。

小结目录

  • 竞态、原子性与锁:从丢失更新推导临界区、互斥锁、自旋锁、原子指令和内存可见性。
  • 信号量与条件变量:区分“保护共享状态”和“等待状态变化”,给出有界缓冲区最小实现。
  • 经典同步问题:用生产者—消费者、读者—写者和哲学家问题训练建模与不变量分析。
  • 死锁、检测与恢复:理解死锁必要条件、资源分配图、预防、避免、检测和恢复。

工具选择的直觉

需求 常见工具
一个时刻只允许一个线程修改状态 互斥锁
临界区极短且不能睡眠 自旋锁或原子操作
等待“队列非空”等条件成立 条件变量
表示有限数量的同类资源 计数信号量
一次性发布初始化结果 once、屏障或安全发布机制

工具名称不是重点。重点是明确共享状态、不变量、谁修改状态、谁等待条件,以及等待和唤醒是否都在同一同步协议中。

学完应能回答

  • 数据竞态、竞态条件和原子性违反有何区别?
  • 为什么检查条件后必须在循环中等待条件变量?
  • 信号量为什么既能表达互斥,也能表达资源数量?
  • 哪四个条件同时成立时才可能死锁?
  • 避免死锁与避免饥饿为什么不是同一件事?