17.8.6 死锁

一个单独的互斥量是不会引起问题的。然而当你同时持有多个互斥量时,各种奇怪的情况就可能发生了。来看一下列表 17-14 这个例子。

Listing 17-14.deadlock_ex

mutex A, B;

thread1 () {
    lock(A);

    lock(B);
    unlock(B);
    unlock(A);
}


thread2() {
    lock(B);

    lock(A);
    unlock(A);
    unlock(B);
}

这段伪代码演示了两个线程一起 hang 住并永远 hang 住的场景。想像一下,因为不幸地调度而产生的如下执行序列:

  • 线程 1 锁住 A; 控制权切换到线程 2。

  • 线程 2 锁住 B; 控制权切换到线程 1。

之后线程尝试:

  • 线程 1 尝试锁 B,但 B 已经被线程 2 锁住了。

  • 线程 2 尝试锁 A,但 A 已经被线程 1 锁住了。

两个线程会永远陷入这种状态。这种线程陷入持有锁且等待其它线程解锁的状态被称为死锁。

引起死锁的原因是不同的线程按照不同的顺序获取锁。所以我们也可以得出一条简单的规则来避免死锁,按顺序对资源上锁就能帮我们节省大量的时间了。


■预防死锁 将你程序中的所有互斥量进行假想排序。只按照这种假想的顺序来对互斥量加锁。

例如,假设我们有互斥量 A,B,C 和 D。将其以 A < B < C < D 的顺序排好序,如果你想要对 D 和 B 同时加锁,那么你就需要按照上述相同的顺序来加锁,也就是说先锁 B,再锁 D。如果这种规则能够保证执行的话,不会有任何两个线程陷入死锁状态。



■Question 362 什么是 Coffman’s conditions? 如何用其来诊断死锁?

■Question 363 如何使用 Helgrind 来检测死锁?


results matching ""

    No results matching ""