Linux——死锁概念介绍和解决方式

目录

一.死锁概念介绍

二.死锁的解决方式

(一).预防死锁

方式一:不请求

方式二:强制剥夺资源

方式三:线性分配资源

(二).避免死锁:银行家算法

总体流程

安全性检查(安全性算法)


一.死锁概念介绍

死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。

就好比和绑匪交赎金时,家属要求先放人再给钱,绑匪要求先交钱再给人,双方达不成一致意见,导致出现“僵死”的局面。

程序层面而言,两个线程各加一个互斥锁mutex,在临界区中试图获取对方的互斥锁,陷入“互相请求对方的锁,但不释放自己锁”的尴尬局面,这就是死锁的一种场景。

图示如下:

达成死锁需要四个必要条件:

①线程互斥。同一时间只能有一个执行流拥有资源

②请求与保持。执行流请求资源时,不能释放已有资源

③不剥夺。执行流已有资源不能被强制剥夺

④循环等待。多个执行流之间形成一种循环等待资源的局面

二.死锁的解决方式

(一).预防死锁

方式一:不请求

剥夺执行流在执行时获取资源的权力,也就是说,执行流在未执行前就获取全部需要的资源,如果有资源未能获取,就先阻塞等待。

缺点:资源利用率低,有锁的情况下其实就是串行执行。

方式二:强制剥夺资源

执行流一旦因为申请资源阻塞,立马释放自己已有的全部资源。

缺点:如果执行流因为释放已有资源导致再次获取时阻塞,从而再次释放,再次申请。假如这样循环多次,肯定会造成资源浪费和性能下降。

方式三:线性分配资源

也就是避免出现循环请求资源。

将所有同类资源按照线性排序。当执行流申请该类型资源时,必须一次性按照线性顺序申请完毕。释放同理。这样就能避免出现循环申请的情况。

图示如下:

(二).避免死锁:银行家算法

总体流程

银行家算法可用于避免死锁的产生,起初是应用在银行内部,确定借贷人是否有能力还贷。当借贷人向银行提出申请时,会根据借贷人项目的最大资金数和本银行现有资产数量确定是否借贷。

在银行家算法里,我们需要四个基本数据结构:

①available向量一维数组,用于确定系统中可利用资源的数量。比如:available[m] = k代表m类资源在系统中有k个可用资源。

②max矩阵二维数组,用于确定每个线程所需的各类资源的总数量(最大数量)。比如:max[i][j] = k代表线程i总共需要k个j类资源。

③allocation矩阵二维数组,代表每个线程已经分配的各类资源数量。比如:allocation[i][j] = k代表已经给线程i分配了k个j类资源。

④need矩阵二维数组,代表每个线程还需要的各类资源数量。比如:need[i][j] = k代表线程i还需要k个j类资源。

需求关系:need[i][j] = max[i][j] - allocation[i][j]

银行家算法具体步骤如下:
设申请的资源量为request[j],首先与need[i][j]相比,<=need[i][j]就进入下一步,否则出错,因为申请的资源量大于所需值。

第二步中,将request[j]与available[j]相比,<=available[j]就进入下一步,否则阻塞,因为当前所需资源的数量不足,需要阻塞等待资源到位。

第三步中,系统将“尝试(假装)”分配相关资源给该线程,并将以下数据修改
available[j] = available[j] - request[j]

allocation[i][j] = allocation[i][j] + request[j]

need[i][j] = need[i][j] - request[j]

第四步中,进行安全性检查。检查系统当前是否在安全状态,如果在安全状态,就 正式分配资源,否则表示系统不安全,让线程等待。

图示如下:

安全性检查(安全性算法)

在安全性检查中,需要两个数据结构:

①work向量一维数组,用于确定此时系统可以提供的各类资源的数量。

②finish向量一维数组(bool类型),如果finish[i] == true,表示i线程有足够的资源能够完成运行,否则说明不能运行完成(即该线程此时不安全)。

具体流程如下:

第一步:从所有线程中找到一个满足need[i][j] < work[j] && finish[j] == false的。即可以提供的资源量能够满足某线程需求,且该线程尚未运行完成。如果有就进入第二步,否则进入第三步。

第二步:该线程获得资源后能够顺利执行完成,且可以释放已有资源,因此,将以下数据修改并返回第一步继续检索线程

work[j] += allocation[j]

finish[j] = true

PS:安全性检查只是一种检查,因此这些数组数据修改都是在模拟资源的申请与释放过程,并不是真正在配分资源。

第三步:此时,已经没有线程满足第一步要求,遍历finish数组,如果有false说明不安全,否则安全

图示如下:

总结一下,在小编看来,安全性检查本质上是判断当前系统中是否有线程已经等待资源配置。虽然线程能够走到安全性检查说明已经有足够的资源供其分配,但是如果检查为不安全代表此时其他线程中有资源需求大于供给的情况并且已经阻塞, 那么当前线程不应该再继续分配资源而是阻塞等待。

对象是过程的抽象,线程是调度的抽象——James O Coplien


如有错误,敬请斧正 

猜你喜欢

转载自blog.csdn.net/weixin_61857742/article/details/128779569