1 什么是多线程竞争
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时回出现竞争状态:即数据几乎同步会被多个线程占用,造成数据混乱,所谓的线程不安全。
而解决线程竞争的一个办法就是——LOCK锁。
锁的好处:
确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行解决多线程资源竞争下的原子操作问题。
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率大大降低。
2 锁的知名问题——死锁
若干子线程在系统资源竞争时,都在等待对某部分资源解除占用状态,结果是谁也不愿意先解锁,互相干等着,程序无法运行下去,这就是死锁。

2.1 死锁产生原因
a. 竞争资源
- 可剥夺资源:
指某进程在获得这类资源后,该资源可以再被其他进程或者系统剥夺,CPU和主存均属于可剥夺资源
- 不可剥夺资源
当系统分配这类资源给进程后,再不能被强制收回,只能等进程用完后自行释放,如磁带、打印机等
- 产生死锁中的竞争资源之一是竞争不可剥夺资源:
例如:系统中只有一台打印机,可供进程P1使用,假定P1已占用了打印机,若P2继续要求打印机打印将阻塞
- 产生死锁中的竞争资源之一是竞争临时资源:
临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁
b. 进程间推进顺序非法
- 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁
- 例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁
2.2 死锁的四个同时满足的必要条件
- 互斥条件
进程要求对所有分配的资源进行排他性控制,即在一段时间内某资源仅为一进程占用
- 请求和保持条件
进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
- 不剥夺条件
进程已获得的资源在未使用之前,不能剥夺,只能在使用完之前自行释放
- 环路等待条件
在发生死锁时,必然存在一个 进程——资源 的环形链:链中每一个进程已获得的资源同时被链中下一个进程所请求。
2.3 死锁的处理方法
为了让死锁不发生,必须设法破坏死锁产生的四个必要条件之一,或者容许死锁产生,但当死锁发生时能检测出死锁并由能力恢复。
死锁的处理策略有:
- 破坏四个必要条件之一
- 用某种方法防止i系统进入不安全状态
- 允许进程在运行中发生死锁,通过系统的检测机构及时地检测出死锁的发生,然后采取某种措施解除死锁。
预防死锁
- 资源一次性分配:**(破坏请求条件)**
一次性分配所有资源,这样就不会再有请求了
- 只要有一个资源得不到分配,也不给这个进程分配其他的资源(破坏请保持条件)
**
- 可剥夺资源:**(**破坏不可剥夺条件)
即当进程获得了某部分资源,但得不到其他资源,则释放已经占有的资源
- 可剥夺资源:**(破坏环路等待条件)**
系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反
预防死锁
- 预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全的状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
- 银行家算法:首先需要定义状态和安全状态的概念。系统的状态是当前给进程分配的资源情况。因此,状态包含两个向量Resource(系统中每种资源的总量)和Available(未分配给进程的每种资源的总量)及两个矩阵Claim(表示进程对资源的需求)和Allocation(表示当前分配给进程的资源)。安全状态是指至少有一个资源分配序列不会导致死锁。当进程请求一组资源时,假设同意该请求,从而改变了系统的状态,然后确定其结果是否还处于安全状态。如果是,同意这个请求;如果不是,阻塞该进程知道同意该请求后系统状态仍然是安全的。
检测死锁
- 首先为每个进程和每个资源指定一个唯一的号码;
- 然后建立资源分配表和进程等待表
解除死锁
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:
- 剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
- 撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。
