死锁

死锁

2025 南京大学《操作系统原理》
死锁

死锁 (Deadlock)

A deadlock is a state in which each member of a group is waiting for another member, including itself, to take action.

center

2025 南京大学《操作系统原理》
死锁

AA-Deadlock

lock(&lk);
// lk->locked == ✅; proceed
...

    // Possibly in interrupt handler
    lock(&lk);
    // while (lk->locked == ❌) ;

看起来很傻,你觉得自己不会犯这错误?

  • 不,你会犯的!
  • 真实系统的复杂性等着你
    • 多层函数调用
    • 隐藏的控制流
2025 南京大学《操作系统原理》
死锁

ABBA-Deadlock

♂ 学家吃饭问题

void T_philosopher() {
    P(&avail[lhs]);
    P(&avail[rhs]);
    // ...
    V(&avail[lhs]);
    V(&avail[rhs]);
}
  • T1T_1: P(0) - 成功, P(1) - 等待
  • T2T_2: P(1) - 成功, P(2) - 等待
  • T3T_3: P(2) - 成功, P(3) - 等待
  • T4T_4: P(3) - 成功, P(4) - 等待
  • T5T_5: P(4) - 成功, P(0) - 等待
2025 南京大学《操作系统原理》
死锁

死锁产生的必要条件

System deadlocks (1971): 把锁看成袋子里的球

  1. Mutual-exclusion - 一个口袋一个球,得到球才能继续
  2. Wait-for - 得到球的人想要更多的球
  3. No-preemption - 不能抢别人的持有的球
  4. Circular-chain - 形成循环等待球的关系

“必要条件”?

  • 打破任何一个条件,就不会发生死锁了
2025 南京大学《操作系统原理》
死锁

死锁产生的必要条件 (cont'd)

“理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。”

不能称为是一个合理的 argument

  • 对于玩具系统/模型
    • 我们可以直接证明系统是 deadlock-free 的
  • 对于真正的复杂系统
    • 哪一个条件最容易打破?
2025 南京大学《操作系统原理》
死锁

在实际系统中避免死锁?

Lock ordering

  • 任意时刻系统中的锁都是有限的
  • 给所有锁编号 (Lock Ordering)
    • 严格按照从小到大的顺序获得锁
    • (这个也容易检查)

Proof (sketch)

  • 任意时刻,总有一个线程获得 “编号最大” 的锁
  • 这个线程总是可以继续运行
2025 南京大学《操作系统原理》
死锁

Lock Ordering: 应用

Linux Kernel: mm/rmap.c

center

2025 南京大学《操作系统原理》
死锁

呃……

Unreliable Guide to Locking: Textbooks will tell you that if you always lock in the same order, you will never get this kind of deadlock. Practice will tell you that this approach doesn't scale: when I create a new lock, I don't understand enough of the kernel to figure out where in the 5000 lock hierarchy it will fit.

The best locks are encapsulated: they never get exposed in headers, and are never held around calls to non-trivial functions outside the same file. You can read through this code and see that it will never deadlock, because it never tries to grab another lock while it has that one. People using your code don't even need to know you are using a lock.

2025 南京大学《操作系统原理》
死锁

死锁:死局

一面是复杂的系统,另一面是不可靠的人

  • 希望
    • 标记 “做一件事” 不被打断
  • 实际
    • “做一件事” 需要拆解成多个步骤
    • 每个步骤需要上正确 (而且尽可能少) 的锁

LockDoc (EuroSys'19)

  • “Only 53 percent of the variables with a documented locking rule are actually consistently accessed with the required locks held.”
2025 南京大学《操作系统原理》
死锁

我们能做的:LockDep

一个简单的想法

  • 每次 acquire/release 都用 printf 打一个日志
    • 如果任何线程既有 ABA \to B 又有 BAB \to A,就报告死锁
    • (这可能导致 false positives,例如存在同步)
      • ABspawnBAA \to B \to \text{spawn} \to B \to A
      • 但这是程序员巨大的心智负担,必须避免

一个相对高效的实现

  • 动态维护 “锁依赖图” 和环路检测
2025 南京大学《操作系统原理》