写给大忙人看的死锁详解(3)

简介: 写给大忙人看的死锁详解(3)

其他问题


下面我们来探讨一下其他问题,包括 通信死锁、活锁是什么、饥饿问题和两阶段加锁


两阶段加锁


虽然很多情况下死锁的避免和预防都能处理,但是效果并不好。随着时间的推移,提出了很多优秀的算法用来处理死锁。例如在数据库系统中,一个经常发生的操作是请求锁住一些记录,然后更新所有锁定的记录。当同时有多个进程运行时,就会有死锁的风险。


一种解决方式是使用 两阶段提交(two-phase locking)。顾名思义分为两个阶段,一阶段是进程尝试一次锁定它需要的所有记录。如果成功后,才会开始第二阶段,第二阶段是执行更新并释放锁。第一阶段并不做真正有意义的工作。


如果在第一阶段某个进程所需要的记录已经被加锁,那么该进程会释放所有锁定的记录并重新开始第一阶段。从某种意义上来说,这种方法类似于预先请求所有必需的资源或者是在进行一些不可逆的操作之前请求所有的资源。


不过在一般的应用场景中,两阶段加锁的策略并不通用。如果一个进程缺少资源就会半途中断并重新开始的方式是不可接受的。


通信死锁


我们上面一直讨论的是资源死锁,资源死锁是一种死锁类型,但并不是唯一类型,还有通信死锁,也就是两个或多个进程在发送消息时出现的死锁。进程 A 给进程 B 发了一条消息,然后进程 A 阻塞直到进程 B 返回响应。假设请求消息丢失了,那么进程 A 在一直等着回复,进程 B 也会阻塞等待请求消息到来,这时候就产生死锁


尽管会产生死锁,但是这并不是一个资源死锁,因为 A 并没有占据 B 的资源。事实上,通信死锁并没有完全可见的资源。根据死锁的定义来说:每个进程因为等待其他进程引起的事件而产生阻塞,这就是一种死锁。相较于最常见的通信死锁,我们把上面这种情况称为通信死锁(communication deadlock)


通信死锁不能通过调度的方式来避免,但是可以使用通信中一个非常重要的概念来避免:超时(timeout)。在通信过程中,只要一个信息被发出后,发送者就会启动一个定时器,定时器会记录消息的超时时间,如果超时时间到了但是消息还没有返回,就会认为消息已经丢失并重新发送,通过这种方式,可以避免通信死锁。


但是并非所有网络通信发生的死锁都是通信死锁,也存在资源死锁,下面就是一个典型的资源死锁。


当一个数据包从主机进入路由器时,会被放入一个缓冲区,然后再传输到另外一个路由器,再到另一个,以此类推直到目的地。缓冲区都是资源并且数量有限。如下图所示,每个路由器都有 10 个缓冲区(实际上有很多)。


image.png


假如路由器 A 的所有数据需要发送到 B ,B 的所有数据包需要发送到 D,然后 D 的所有数据包需要发送到 A 。没有数据包可以移动,因为在另一端没有缓冲区可用,这就是一个典型的资源死锁。


活锁


你会发现一个很有意思的事情,死锁就跟榆木脑袋一样,不会转弯。我看过古代的一则故事:


image.png


如果说死锁很痴情的话,那么活锁用一则成语来表示就是 弄巧成拙


某些情况下,当进程意识到它不能获取所需要的下一个锁时,就会尝试礼貌的释放已经获得的锁,然后等待非常短的时间再次尝试获取。可以想像一下这个场景:当两个人在狭路相逢的时候,都想给对方让路,相同的步调会导致双方都无法前进。


现在假想有一对并行的进程用到了两个资源。它们分别尝试获取另一个锁失败后,两个进程都会释放自己持有的锁,再次进行尝试,这个过程会一直进行重复。很明显,这个过程中没有进程阻塞,但是进程仍然不会向下执行,这种状况我们称之为 活锁(livelock)


饥饿


与死锁和活锁的一个非常相似的问题是 饥饿(starvvation)。想象一下你什么时候会饿?一段时间不吃东西是不是会饿?对于进程来讲,最重要的就是资源,如果一段时间没有获得资源,那么进程会产生饥饿,这些进程会永远得不到服务。


我们假设打印机的分配方案是每次都会分配给最小文件的进程,那么要打印大文件的进程会永远得不到服务,导致进程饥饿,进程会无限制的推后,虽然它没有阻塞。


总结


死锁是一类通用问题,任何操作系统都会产生死锁。当每一组进程中的每个进程都因等待由该组的其他进程所占有的资源而导致阻塞,死锁就发生了。这种情况会使所有的进程都处于无限等待的状态。


死锁的检测和避免可以通过安全和不安全状态来判断,其中一个检测方式就是银行家算法;当然你也可以使用鸵鸟算法对死锁置之不理,但是你肯定会遭其反噬。


也可以在设计时通过系统结构的角度来避免死锁,这样能够预防死锁;也可以破坏死锁的四个条件来破坏死锁。资源死锁并不是唯一性的死锁,还有通信间死锁,可以设置适当的超时时间来完成。


活锁和死锁的问题有些相似,它们都是一种进程无法继续向下执行的状态。由于进程调度策略导致尝试获取进程的一方永远无法获得资源后,进程会导致饥饿的出现。


尾声



提出一个勘误,已反馈给出版社


image.png



            </div>
目录
相关文章
|
前端开发 JavaScript 安全
|
弹性计算 运维 监控
深度解读:为什么会有ECS经济型e实例及其背后思考
本文浅入深出的分析了ECS经济型e实例的产品思考,怎么更好让ECS助力客户业务。
|
7月前
|
开发工具 Android开发 iOS开发
零基础构建即时通讯开源项目OpenIM移动端-Flutter篇
OpenIM 为开发者提供开源即时通讯 SDK,作为 Twilio、Sendbird 等云服务的替代方案。借助 OpenIM,开发者可以构建安全可靠的即时通讯应用,如 WeChat、Zoom、Slack 等。 本仓库基于开源版 OpenIM SDK 开发,提供了一款基于 Flutter 的即时通讯应用。您可以使用此应用程序作为 OpenIM SDK 的参考实现。 开发环境 在开始开发之前,请确保您的系统已安装以下软件: 操作系统:macOS 14.6 或更高版本 Flutter:版本 3.24.5(根据官网步骤进行安装) Git:用于代码版本控制 同时,您需要确保已经部署了最
399 10
|
12月前
|
安全 关系型数据库 Shell
Web安全-浅析CSV注入漏洞的原理及利用
Web安全-浅析CSV注入漏洞的原理及利用
533 3
|
机器学习/深度学习 人工智能 运维
智能化运维:AI在IT管理中的革新作用
随着人工智能(AI)技术的飞速发展,其在信息技术(IT)运维领域的应用正逐渐成熟,并开始引领一场革命。本文将探讨AI技术如何优化传统的IT运维流程,提高效率与响应速度,并预测未来运维的发展方向。通过分析实际案例和最新的研究成果,本文旨在为读者提供一个关于AI在现代IT运维中角色和影响的全面视角。
|
运维 监控 安全
构建高效自动化运维体系:策略与实践
【4月更文挑战第28天】在信息技术日新月异的今天,高效的运维管理对于确保系统稳定性和业务连续性至关重要。本文将探讨如何通过自动化工具和策略构建一个灵活、可靠的运维体系,以适应快速变化的技术环境和业务需求。我们将从持续集成/持续部署(CI/CD)的实践出发,结合监控、日志分析、故障响应等关键环节,详细阐述自动化运维体系的构建过程及其带来的效益。通过实例分析,本文旨在为读者提供一套可行的自动化运维解决方案,以及实施过程中可能遇到的挑战和应对策略。
|
移动开发 前端开发 搜索推荐
【CSDN创作优化1】个人简介优化 html font属性
【CSDN创作优化1】个人简介优化 html font属性
121 0
|
前端开发 JavaScript 安全
SpringBoot+Vue豆宝社区前后端分离项目手把手实战系列教程05---每日一句功能实现
SpringBoot+Vue豆宝社区前后端分离项目手把手实战系列教程05---每日一句功能实现
252 0
|
存储 运维 监控
cephadm 安装部署 ceph 集群
块存储:提供像普通硬盘一样的存储,为使用者提供“硬盘” 文件系统存储:类似于NFS的共享方式,为使用者提供共享文件夹 对象存储:像百度云盘一样,需要使用单独的客户端 ceph还是一个分布式的存储系统,非常灵活。如果需要扩容,只要向ceph集中增加服务器即可。ceph存储数据时采用多副本的方式进行存储,生产环境下,一个文件至少要存3份。ceph默认也是三副本存储。
787 0
|
机器学习/深度学习 PyTorch 算法框架/工具
从零开始学Pytorch(七)之卷积神经网络基础
从零开始学Pytorch(七)之卷积神经网络基础
从零开始学Pytorch(七)之卷积神经网络基础