OS chapter 2 Deadlock and starvation
产生死锁与互斥的原因;
解决死锁;
死锁与同步的经典问题:哲学家进餐问题
原因:因为进程间的竞争资源或通信不当,造成进程的永久信阻塞;
没有有效的解决方法;
可能会有单进程的死锁;
1 /* P */ 2 get A; 3 ... 4 get B; 5 ... 6 release A; 7 ... 8 release B; 9 10 /* Q */ 11 get B; 12 ... 13 get A; 14 ... 15 release B; 16 ... 17 release A;
// 可能会出现死锁
可重用资源:处理器、I/O通道、主存、辅存等
进程占有一个资源请求其它资源就可能会出现死锁;
可消耗资源:中断、消息等
如两个进程都是采用阻塞接收消息,且两个进程分别要接收对方的消息,则可能出现阻塞;
产生死锁的原因
- 互斥使用
- 占有并等待
- 不剥夺
- 环路等待
死锁的预防
以四个条件为考虑,分析是一个问题,但工程来说是不可用,降低了系统的性能;
间接方法
- 互斥:不能禁止;
- 保持与等待:要求进程一次性申请其所需资源,若系统中没有足够的资源可能造成进程阻塞,使得系统效率低;
- 不剥夺:高优先权剥夺低优先权进程对资源的使用权;
- 环路等待:
直接方法
- 禁止环路等待:对系统资源类型进行排队,进程对某类资源的申请只能按序号递增的方式进行;
避免死锁 Deadlock Avoidance
在为进程分配资源之前,首先通过计算判断此次分配是否分导致死锁,只有不导致死锁的分配才是可行的。
银行家算法
安全状态:系统为某个进程序列分配其所需的资源直到最大需求,使得每个进程都可以顺序完成则系统称为安全状态;
通过需求矩阵、已分配矩阵、可用资源矩阵、还要的资源矩阵,即可知道按什么顺序执行进程不会进入不安全状态;
为了实现银行家算法,系统中必须实现某些数据结构;
数据结构
- 资源可以向量
- 最大需求矩阵n*m
- 分配矩阵n*m
- 还需矩阵n*m
特点:
- 必须预先知道每个进程需要的资源总量
- 每次都要算,对系统性能损耗大
- 进程必须释放资源,这个不一定
检测死锁 Deadlock Detection
周期性的执行死锁检测,看系统中是否有环路等待;
哲学家进餐问题
要求:使所有哲学家都能进餐,且不会有人出现饥饿;
1 /* 会造成死锁的算法 */ 2 semaphore fork[5] = {1,1,1,1,1}; /* 筷子信号量初始化为1 */ 3 int i; 4 while(1) 5 { 6 think; 7 wait(fork[i]); /*拿起左边的筷子 */ 8 wait(fork[(i+1)%5]); /*拿起右边的筷子 */ 9 eat; 10 signal(fork[(i+1)%5]); 11 signal(fork[i]); 12 }
上面这个算法会造成死锁,因为如果5个哲学家都运行到7的时候被中断,则会死锁;
原因是系统中同时运行的进程太多了,系统处于高竞争状态;所以可以考虑减少同时运行的进程数,即挂起一定数量的进程;
1 /* 改进的算法 */ 2 semaphore fork[5] = {1,1,1,1,1}; /* 筷子信号量初始化为1 */ 3 int i; 4 semaphore room = 4; /* 信号量初始化为4,最多允许4个哲学家同时进来 */ 5 while(1) 6 { 7 think; 8 wait(room); /* 当room<=0则挂起 */ 9 wait(fork[i]); /*拿起左边的筷子 */ 10 wait(fork[(i+1)%5]); /*拿起右边的筷子 */ 11 eat; 12 signal(fork[(i+1)%5]); 13 signal(fork[i]); 14 signal(room); /* 唤醒队列中的哲学家 */ 15 }
浙公网安备 33010602011771号