并发编程的本质

人类是 sequential creature

  • 我们只能用 sequential 的方式来理解并发
    • 程序分成若干 “块”,每一块看起来都没被打断 (原子)
    • 具有逻辑先后的 “块” 被正确同步
      • 例子:produce → (happens-before) → consume

并发控制的机制完全是 “后果自负” 的

  • 互斥锁 (lock/unlock) 实现原子性
    • 忘记上锁——原子性违反 (Atomicity Violation, AV)
  • 条件变量/信号量 (wait/signal) 实现先后顺序同步
    • 忘记同步——顺序违反 (Order Violation, OV)

那么,程序员用的对不对呢?

“Empirical study” 实证研究

  • 收集了 105 个真实系统的并发 bugs
    • MySQL (14/9), Apache (13/4), Mozilla (41/16), OpenOffice (6/2)
    • 观察是否存在有意义的结论

97% 的非死锁并发 bug 都是原子性或顺序错误

原子性违反 (AV)

“ABA”

  • 我以为一段代码没啥事呢,但被人强势插入了
  • 即便分别上锁 (消除数据竞争),依然是 AV
    • Diablo I 里复制物品的例子
    • Therac-25 中 “移动 Mirror + 设置状态”

原子性违反 (cont'd)

操作系统中还有更多的共享状态

  • “TOCTTOU” - time of check to time of use

顺序违反 (OV)

“BA”

  • 怎么就没按我预想的顺序来呢?
    • 例子:concurrent use after free