多进程模型
临界区保护
临界区指的是一个访问共用资源的程序片段,且资源具有互斥性。当有进程进入临界区段时,其他线程或是进程必须等待
PV操作:进入临界区的操作,分布在临界区头尾。
进入临界区的调度原则:
-
如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。
-
任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待。
-
进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。
-
如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。
调度算法:
-
面包店算法:进入商店的顾客获取一个号码,号码小的先服务,相同的号码,名字靠前先服务。依然是轮转和标记的结合。
boolean choosing[n];//表示进程是否在取号 int number[n];//记录每个进程取到的号码 //这些数据结构分别初始化为false和0,为了方便,定义如下符号: //若a<c或a==c和b<d同时成立,(a,b)<(c,d) do{ choosing[i] = true; number[i] = max{number[0],number[1],…,number[n-1]}+1;//选号码 choosing[i] = false; for(j = 0; j<n; j++){ while (choosing[j]); while ((number[j] != 0) && (number[j],j)<(number[i],i)); }; //临界区 number[i] = 0; //其余部分 }while(1);
-
阻止中断
一个进程想要执行,就要获得锁(进入临界区),这个进程想要执行的前提是被调度!因此只需要阻止调度,就可以阻止它进入临界区。不被中断,就不被调度。只需要阻止中断即可(CPU对应的INTR置1)。 这种方法只对单CPU有效,多CPU无效。
-
原子指令法
对临界区硬件上锁,通过硬件原子指令实现,因此不会被打断
死锁的解决
-
预防避免死锁的办法
注意:由于互斥条件是非共享设备所必需的,不能改变
-
破坏“请求和保持”条件:规定所有进程在开始运行之前,都必须一次性的申请其在整个运行过程所需要的全部资源。
优点:简单,安全。 缺点:资源严重浪费,恶化了系统的利用率;
-
破坏“不剥夺”条件:当一个已经持有资源的进程再提出新的资源请求而不能立即得到满足时,必须释放它已经保持了的所有资源,待以后需要时再重新申请。
缺点:实现复杂,反复释放和获取资源开销大
-
破坏“环路等待”条件:将所有的资源按类型进行线性排队,并赋予不同的序号。所有进程请求资源必须按照资源递增的次序提出,防止出现环路。
缺点:为了保证资源顺序会有额外开销。
-
银行家算法
由迪杰斯特拉1965年提出,算法的核心是通过剩余可分配资源数判断是否会出现死锁,若线程申请的资源可能造成死锁安全问题,则仅分配至安全极限或不分配。操作系统就好像一个银行家,线程就像企业,企业需要申请贷款,则银行家会判断贷款给企业家后是否会造成余额不足,如果会则不要贷那么多给企业或不贷给企业。 算法用到的数据结构有:可利用资源向量Available,最大需求矩阵Max,分配矩阵Allocation,需求矩阵Need,上述矩阵存在关系:
Need[i,j]=Max[i,j]-Allocation[i,j]
。
-
-
检测死锁和消除死锁
死锁检测:开额外的线程定时检查,遍历所有进程,当前进程未被标记 且 需要的资源系统能否满足?可以并标记为结束;若不能满足则认为出现死锁。
死锁消除:要么先抢占一些资源分配给死锁进程,要么终结出现死锁的进程。
-
终结死锁
检测和消除开销都很大,而且复杂,有些时候就直接终结死锁,比如个人PC卡死后直接重启即可。