Linux操作系统问题-----死锁产生的原因与解决办法

简介: Linux操作系统问题-----死锁产生的原因与解决办法

一、产生死锁的原因(两个):

由竞争资源引起死锁:多个进程,共享资源,资源不足,竞争资源。


竞争可剥夺性资源。譬如:CPU,可由优先级高的进程剥夺优先级低的进程的处理机。

竞争非剥夺性资源。譬如:系统中只有一台打印机R1和一台读卡机R2,进程P1和P2之间共享这些资源。当P1占用了R1会进一步要求R2的使用,但是此时P2占用了R2进一步请求着R1的使用;则P1与P2之间陷入了僵局,构成了死锁。


例子:


A有纸,B有笔


A:你不给我笔,我就写不了作业


B:你不给我纸,我就写不了作业



竞争临时性资源。譬如:一个进程需要使用另一个进程产生的结果,这属于一种临时性的资源,过了一段时间之后就没用了,也会产生死锁。(如下图所示:P1、P2、P3是进程,S1、S2、S3是产生的临时资源)


例子:


A要前进2步,到桌子前,再后退2步。


但如果执行顺序不合理:A先后退,就永远到不了桌子前,触发不了后续动作,就会死锁。



进程推进顺序不当引起死锁:进程运行过程中,请求和释放资源的顺序不当,而导致进程死锁。


二、产生死锁的四个必要条件:

① 互斥条件——进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占有。


② 请求和保持条件——当进程因请求资源而阻塞时,对已获得的资源保持不放。


③ 不剥夺条件——进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。


④ 环路等待条件——在发生死锁时必然存在一个“进程—资源”的环形链。


三、解决死锁的基本方法(四种):

① 预防死锁——通过设置某些限制条件,以破坏产生死锁的四个必要条件中的一个或几个,来防止发生死锁。


② 避免死锁——在资源的动态分配过程中,使用某种方法去防止系统进入不安全状态,从而避免了死锁的发生。


③ 检测死锁——检测死锁方法允许系统运行过程中发生死锁。但通过系统所设置的检测机构,可以及时检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中消除所发生的死锁。


④ 解除死锁——解除死锁是与检测死锁相配套的一种设施,用于将进程从死锁状态下解脱出来。常用的方法是撤销或者挂起一些进程,以便于释放出一些资源,再将它分配给已经处于阻塞的进程,使其转换为就绪状态可以继续运行。


四、如何避免死锁参考

在有些情况下死锁是可以避免的。三种用于避免死锁的技术:


加锁顺序(线程按照一定的顺序加锁)

加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

死锁检测

加锁顺序


当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。


如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。


如果一个线程(比如线程3)需要一些锁,那么它必须按照确定的顺序获取锁。它只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。


例如,线程2和线程3只有在获取了锁A之后才能尝试获取锁C(译者注:获取锁A是获取锁C的必要条件)。因为线程1已经拥有了锁A,所以线程2和3需要一直等到锁A被释放。然后在它们尝试对B或C加锁之前,必须成功地对A加了锁。


按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。


加锁时限

另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。


死锁检测

死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。


每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。


当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。


当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。


那么当检测出死锁时,这些线程该做些什么呢?


一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(原因同超时类似,不能从根本上减轻竞争)。


一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。


总结:死锁是系统资源竞争的结果,要尽量避免,增强代码的逻辑以及对操作系统的理解。

目录
相关文章
|
16天前
|
监控 Unix Linux
Linux操作系统调优相关工具(四)查看Network运行状态 和系统整体运行状态
Linux操作系统调优相关工具(四)查看Network运行状态 和系统整体运行状态
30 0
|
18天前
|
Linux 编译器 开发者
Linux设备树解析:桥接硬件与操作系统的关键架构
在探索Linux的庞大和复杂世界时🌌,我们经常会遇到许多关键概念和工具🛠️,它们使得Linux成为了一个强大和灵活的操作系统💪。其中,"设备树"(Device Tree)是一个不可或缺的部分🌲,尤其是在嵌入式系统🖥️和多平台硬件支持方面🔌。让我们深入了解Linux设备树是什么,它的起源,以及为什么Linux需要它🌳。
Linux设备树解析:桥接硬件与操作系统的关键架构
|
25天前
|
Linux 数据安全/隐私保护 Windows
aes加密在linux下会生成随机key的解决办法
aes加密在linux下会生成随机key的解决办法
14 2
|
1月前
|
Linux 数据安全/隐私保护 虚拟化
Linux技术基础(1)——操作系统的安装
本文是龙蜥操作系统(Anolis OS) 8.4 的安装指南,用户可以从[龙蜥社区下载页面](https://openanolis.cn/download)获取ISO镜像。安装方法包括物理机的光驱和USB闪存方式,以及虚拟机中的VMware Workstation Pro设置。安装过程涉及选择语言、配置安装目标、选择软件集合和内核,设置Root密码及创建新用户。安装完成后,可通过文本模式或图形化界面验证系统版本,如Anolis OS 8.4,标志着安装成功。
|
1月前
|
存储 缓存 算法
Linux--系统结构与操作系统
Linux--系统结构与操作系统
|
1月前
|
安全 Linux 网络安全
如何在 VM 虚拟机中安装 Red Hat Enterprise Linux 9.3 操作系统保姆级教程(附链接)
如何在 VM 虚拟机中安装 Red Hat Enterprise Linux 9.3 操作系统保姆级教程(附链接)
93 0
|
16天前
|
Linux
Linux操作系统调优相关工具(三)查看IO运行状态相关工具 查看哪个磁盘或分区最繁忙?
Linux操作系统调优相关工具(三)查看IO运行状态相关工具 查看哪个磁盘或分区最繁忙?
21 0
|
2天前
|
Linux 数据安全/隐私保护
Linux系统忘记密码的三种解决办法
这篇博客介绍了三种在Linux忘记密码时重置登录密码的方法:1) 使用恢复模式,通过控制台界面以管理员权限更改密码;2) 利用Linux Live CD/USB启动,挂载硬盘分区并使用终端更改密码;3) 进入单用户模式,自动以管理员身份登录后重置密码。每个方法都提供了详细步骤,提醒用户在操作前备份重要数据。
|
16天前
|
Linux
linux 超过4个G的文件传不上去的解决办法
linux 超过4个G的文件传不上去的解决办法
9 0
|
1月前
|
存储 Shell Linux
【Shell 命令集合 网络通讯 】⭐Linux 显示当前系统的主机名和操作系统类型 uuname命令 使用教程
【Shell 命令集合 网络通讯 】⭐Linux 显示当前系统的主机名和操作系统类型 uuname命令 使用教程
29 0