本文共 5909 字,大约阅读时间需要 19 分钟。
指一次仅允许一个进程使用的资源称为临界资源
,例如物理设备中的打印机。对这种临界资源的访问,必须互斥地进行,在每个进程中,访问临界资源的那段代码称为临界区。为了进入临界区使用临界资源,在进入区要检查是否可进入临界区,若要进入临界区,则应该设置正在访问临界区的标志,以阻止其他进程同时进入临界区
。临界区
:进程中访问临界资源的那段代码,也称临界段
。用于将正在访问临界区的标志清除
。代码中的其余部分
。do{ entry section; //进入区 critical section; // 临界区 exit section; // 退出区 remainder section; //剩余区 }while(ture);
直接制约关系
,指为完成某种任务而建立的两个或多个进程,这些进程因为需要某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系
。进程间的制约关系源于它们之间的相互合作。间接制约关系
。当一个进程进入临界区使用资源时,另一个进程必须等待,当占用临界资源的进程退出临界区时,另一进程才允许访问此临界资源
。空闲让进
:临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。忙则等待
:当已有进程进入临界区时,其他试图进入临界区的进程必须等待。有限等待
:对请求访问的进程,应保证能在有限时间内进入临界区。让权等待
:当进程进入临界区时,应立即释放处理器,防止进程忙等待。软件实现方法和硬件实现方法
。在进入区设置并检查一些标志来标明是否有进程在临界区中
,若已有进程在临界区,则在进入区通过循环检查进行等待,进程离开临界区后则在退出区修改标志。设置一个公用整型变量 turn
,用于指示被允许进入临界区的进程编号;当 turn=0
时,允许进程进入临界区
;该算法确保每次只允许一个进程进入临界区。①进程: while(trun!=0); critical section; turn=1; remainder section; ②进程: while(turn!=1); critical section; turn=0; remainder section;
在每个进程访问临界区资源之前,先查看临界资源是否正在被使用,若是则进程等待;若不是,进程才进入临界区
。该算法设置一个 flag[i]
表示某个进程是否进入临界区
,true 表示进入,false 表示未进入。pi进程: while(flag[j]); ① flag[i]=true; ③ critical section; flag[i]=false; remainder section; pj 进程: while[flag[i]); ② flag[j]=true; ④ critical section; flag[j]=false; remainder section;
不用交替进入,可连续使用
。两个进程可能同时进入临界区
,按序列①②③④执行时;因为在检查对方的 flag 后切换自己的 flag 前有一段时间,结果都检查通过。问题原因在于检查和修改操作不能一次进行。该算法先将自己的标志设置为 true,再检查对方的状态标志,若对方为 true,则进程等待;否则进入临界区
。pi 进程: flag[i]=ture; while(flag[j]); critical section; flag[i]=false; remainder section; pj 进程: flag[j]=true; while(flag[i]); critical section; flag[j]=false; remainder section;
两个进程几乎同时都想进入临界区时,分别同时将自己的标志设置为 true,并且同时检测对方的状态,发现对方也要进入临界区,双方互相谦让,从而导致“饥饿”现象
。flag 和 turn
,每个进程先设置自己的 flag 再设置 turn 标志,再同时检测另一个进程的状态标志和不允许进入标志
,保证两个进程同时要求进入临界区时,只允许一个进程进入临界区:pi 进程 flag[i]=true;turn=j; while(flag[j]&&turn==j); critical section; flag[i]=false; remainder section; pj 进程: flag[j]=true;turn=i; while(flag[i]&&turn==i); critical section; remiander section;
利用 flag 解决临界资源的互斥访问
,利用 turn 解决“饥饿”现象
。特殊的硬件指令
,允许对一个字中的内容进行检测和修正,或对两个字的内容进行交换等。通过硬件支持实现临界段问题的方法称为低级方法,或称元方法
。禁止一切中断发生
,称之为屏蔽中断、关中断
。因为 CPU 只在发生中断时引起进程切换,因此屏蔽中断能够保证当前运行的进程让临界区代码顺利执行完,进而保证互斥的正确实现,然后再开中断。典型模型如下:. . . 关中断 临界区 开中断 . . .
限制了处理机交替执行程序的能力
,从而降低执行效率
,而且风险大
:将关中断权利下放给用户程序,若用户程序关中断后不再开中断,系统可能因此终止
。原子操作
,其功能是读出指定标志后把该标志设置为真
,功能描述:boolean TestAndSet(boolean *lock){ boolean old; old=*lock; *lock=true; return old; }
为每个临界资源设置一个共享布尔变量 lock
,true 表示占用,初值为 false。进程访问临界资源前调用 TestAndSet 检测 lock,若无占用则进程直接访问临界资源,反之则循环检测直到占用临界资源的进程退出,如下:while(TestAndSet(&lock)); critical section; lock=false; remainder section;
交换两个字的内容
,如下:Swap(boolean *a, boolean *b){ boolean temp; temp=*a; *a=*b; *b=temp; }
每个临界资源设置一个共享布尔变量 lock
,初值为 false;再为每个进程设置一个布尔变量 key
。进程进入临界区前,利用 Swap 交换 lock 和 key,检测 key 的状态;有进程占用临界区则重复交换和检测过程,直到进程退出。key=true; while(key!=false) Swap(&lock,&key); critical section; lock=false; remainder section;
适用于任意数目的进程,不管单处理机还是多处理机;简单、容易验证其正确性;支持进程内有多个临界区
。进程等待进入临界区时要耗费处理机时间,不能实现让权等待;从进程中随机选取一个进入临界区,有的进程可能一直选不上,从而导致“饥饿”现象
。信号量机制是一种功能较强的机制,可用于解决互斥与同步问题,只能被两个标准的原语 wait(s) 和 singal(S) 访问,也可记为“P 操作”和“V 操作”
。定义为一个表示资源数目的整型量 S
,wait 和 singal 操作可描述为:wait(s){ while(S<=0); S=S-1; } signal(S){ S=S+1; }
代表资源数目的整型变量 value
外,还有一个进程链表 L
,用于链接所有等待该资源的进程;因此此种机制下不存在“忙等”现象。记录型信号量可描述如下:typdef struct{ int value; struct process *L; }semaphore;
void wait(semphore S){ S.value--; //请求一个该类资源 if(S.value<0){//当该类资源已经分配完 add this process to S.L; // 进入等待队列 block(S.L); // 进行自我阻塞 } } void singal(semaphore S){ S.value++; // 释放资源 if(S.value<=0){ // 判断是否有等待该资源的进程 remove a process P from S.L; // 从等待队列中选择一个进程 wakeup(P); // 唤醒该进程 } }
semaphore S=0; P1(){ … x; // 语句 x,为 P2 要用到的结果 V(S); // 告诉 P2,语句 x 已经完成 … } P2(){ … P(S); //检测 x 语句是否完成,若没有,进程阻塞 y; // 当语句 x 完成,运行 y 语句。 }
semaphore S=1; P1(){ … P(S); //准备访问临界资源,加锁 critical section; V(S); // 访问结束,解锁 … } P2(){ … P(S); //准备访问临界资源,加锁 critical section; V(S); // 访问结束,解锁 … }
利用共享数据结构抽象地表示系统中地共享资源,而把对该数据结构实施地操作定义为一组过程;这个代表共享资源地数据结构,以及由对该共享数据结构实施操作地一组过程所组成地资源管理程序,称为管程
。管程的名称
; ② 局部于管程内部的共享结构数据说明
; ③ 对该数据结构进行操作的一组过程或函数
; ④ 对局部于管程内部的共享数据设置初始值的语句
。monitor Demo{// 定义一个名称为 Demo 的管程 // 定义共享数据结构,对应系统中的某种共享资源 typdef struct S; // 对共享数据结构初始化 init func(){ S=5; // 初始资源数量 } // 过程 1:申请一个资源 take_away(){ some code; // 对共享数据结构 x 的一系列处理 S--; // 可用资源数减一 … } // 过程2:归还资源 give_back(){ some code; S++; // 可用资源数加一 } }
monitor Demo{ typdef struct S; condition x; init func(){}; take_away(){ if(S<=0) x.wait(); … } give_back(){ … if(有进程在等待) x.singal(); } }
条件量和信号量的异同
:条件量的 wait/singal 操作类似信号量的 P/V 操作,可以实现进程的阻塞/唤醒
。条件变量时“没有值”的,仅实现了“排队等待”功能;而信号量是“有值”的,信号量的值反映了剩余资源数,而管程中剩余资源数用共享数据结构记录
。转载地址:http://rmqgn.baihongyu.com/