6.7 其他问题

在本节中,我们会讨论一些和死锁相关的问题,包括两阶段加锁、通信死锁、活锁和饥饿。

6.7.1 两阶段加锁

虽然在一般情况下避免死锁和预防死锁并不是很有希望,但是在一些特殊的应用方面,有很多卓越的专用算法。例如,在很多数据库系统中,一个经常发生的操作是请求锁住一些记录,然后更新所有锁住的记录。当同时有多个进程运行时,就有出现死锁的危险。

常用的方法是两阶段加锁(two-phase locking)。在第一阶段,进程试图对所有所需的记录进行加锁,一次锁一个记录。如果第一阶段加锁成功,就开始第二阶段,完成更新然后释放锁。在第一阶段并没有做实际的工作。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

如果在第一阶段某个进程需要的记录已经被加锁,那么该进程释放它所有加锁的记录,然后重新开始第一阶段。从某种意义上说,这种方法类似于提前或者至少是未实施一些不可逆的操作之前请求所有资源。在两阶段加锁的一些版本中,如果在第一阶段遇到了已加锁的记录,并不会释放锁然后重新开始,这就可能产生死锁。

不过,在一般意义下,这种策略并不通用。例如,在实时系统和进程控制系统中,由于一个进程缺少一个可用资源就半途中断它,并重新开始该进程,这是不可接受的。如果一个进程已经在网络上读写消息、更新文件或从事任何不能安全地重复做的事,那么重新运行进程也是不可接受的。只有当程序员仔细地安排了程序,使得在第一阶段程序可以在任意一点停下来,并重新开始而不会产生错误,这时这个算法才可行。但很多应用并不能按这种方式来设计。