旌旗灯号量机构是一种功用较强的机制,可用来处理互斥与同步的成绩,它只能被两个规范的原语wait(S)和signal(S)来拜访,也可以记为“P操作”和“V操作”。
原语是指完成某种功用且不被联系不被中缀履行的操作序列,平日可由硬件来完成完成不被联系履行特征的功用。如前述的“Test-and-Set”和“Swap”指令,就是由硬件完成的原子操作。原语功用的不被中缀履行特征在单处置机时可由软件经过屏障中缀办法完成。
原语之所以不克不及被中缀履行,是由于原语对变量的操作进程假如被打断,能够会去运转另一个对统一变量的操作进程,从而呈现临界段成绩。假如可以找到一种处理临界段成绩的元办法,就可以完成对共享变量操作的原子性。
整型旌旗灯号量
整型旌旗灯号量被界说为一个用于表现资本数量的整型量S,wait和signal操作可描绘为:
wait(S){ while (S<=0); S=S-1; } signal(S){ S=S+1; }
wait操作中,只需旌旗灯号量S<=0,就会不时地测试。因而,该机制并未遵照“让权等候” 的原则,而是使过程处于“忙等”的形态。
记载型旌旗灯号量
记载型旌旗灯号量是不存在“忙等”景象的过程同步机制。除了需求一个用于代表资本数量的整型变量value外,再添加一个过程链表L,用于链接一切等候该资本的过程,记载型旌旗灯号量是因为釆用了记载型的数据构造得名。记载型旌旗灯号量可描绘为:
typedef struct{ int value; struct process *L; } semaphore;
响应的wait(S)和signal(S)的操作如下:
void wait (semaphore S) { //相当于请求资本 S.value--; if(S.value<0) { add this process to S.L; block(S.L); } }
wait操作,S.value--,表现过程恳求一个该类资本,当S.value<0时,表现该类资本已分派终了,因而过程应挪用block原语,停止自我壅塞,保持处置机,并拔出到该类资本的等候队列S.L中,可见该机制遵照了“让权等候”的原则。
void signal (semaphore S) { //相当于释放资本 S.value++; if(S.value<=0){ remove a process P from S.L; wakeup(P); } }
signal操作,表现过程释放一个资本,使零碎中可供分派的该类资本数增1,故S.value++。若加1后仍是S.value<=0,则表现在S.L中仍有等候该资本的过程被壅塞,故还应挪用wakeup 原语,将S.L中的第一个等候过程叫醒。
应用旌旗灯号量完成同步
旌旗灯号量机构能用于处理过程间各类同步成绩。设S为完成过程P1、P2同步的公共旌旗灯号量,初值为0。过程P2中的语句y要运用过程P1中语句x的运转后果,所以只要当语句x履行完成之后语句y才可以履行。其完成过程同步的算法如下:
semaphore S = 0; //初始化旌旗灯号量 P1 ( ) { // … x; //语句x V(S); //通知过程P2,语句乂曾经完成 } P2()){ // … P(S) ; //反省语句x能否运转完成 y; // 反省无误,运转y语句 // … }
应用旌旗灯号量完成过程互斥
旌旗灯号量机构也能很便利地处理过程互斥成绩。设S为完成过程Pl、P2互斥的旌旗灯号量,因为每次只许可一个过程进入临界区,所以S的初值应为1(即可用资本数为1)。只需把临界区置于P(S)和V(S)之间,即可完成两过程对临界资本的互斥拜访。其算法如下:
semaphore S = 1; //初化旌旗灯号量 P1 ( ) { // … P(S); // 预备开端拜访临界资本,加锁 // 过程P1的临界区 V(S); // 拜访完毕,解锁 // … } P2() { // … P(S); //预备开端拜访临界资本,加锁 // 过程P2的临界区; V(S); // 拜访完毕,解锁 // … }
互斥的完成是分歧过程对统一旌旗灯号量停止P、V操作,一个过程在胜利地对旌旗灯号量履行了 P操作落后入临界区,并在加入临界区后,由该过程自身对该旌旗灯号量履行V操作,表现以后没有过程进入临界区,可以让其他过程进入。
应用旌旗灯号量完成前驱关系
旌旗灯号量也可以用来描绘程序之间或许语句之间的前驱关系。图2-8给出了一个前驱图,个中S1, S2, S3, …, S6是最复杂的程序段(只要一条语句)。为使各程序段能准确履行,应设置若干个初始值为“0”的旌旗灯号量。例如,为包管S1 -> S2、 S1 -> S3的前驱关系,应辨别设相信号量a1、a2。异样,为了包管 S2 -> S4、S2 ->S5、S3 -> S6、S4 -> S6、S5 -> S6,应设相信号量bl、b2、c、d、e。
图2-8 前驱图举例
完成算法如下:
semaphore al=a2=bl=b2=c=d=e=0; //初始化旌旗灯号量 S1() { // … V(al); V(a2) ; //S1曾经运转完成 } S2() { P(a1); //反省S1能否运转完成 // … V(bl); V(b2); // S2曾经运转完成 } S3() { P(a2); //反省S1能否曾经运转完成 // … V(c); //S3曾经运转完成 } S4() { P(b1); //反省S2能否曾经运转完成 // … V(d); //S4曾经运转完成 } S5() { P(b2); //反省S2能否曾经运转完成 // … V(e); // S5曾经运转完成 } S6() { P(c); //反省S3能否曾经运转完成 P(d); //反省S4能否曾经运转完成 P(e); //反省S5能否曾经运转完成 // …; }
剖析过程同步和互斥成绩的办法步调
1) 关系剖析。找出成绩中的过程数,而且剖析它们之间的同步和互斥关系。同步、互斥、前驱关系直接依照下面例子中的经模范式改写。
2) 整顿思绪。找出处理成绩的症结点,而且依据做过的标题找出处理的思绪。依据过程的操作流程肯定P操作、V操作的大致次序。
3) 设相信号量。依据下面两步,设置需求的旌旗灯号量,肯定初值,完美整顿。