进程同步问题(二)——信号量机制

一、信号量机制

  1. 简介:
    信号量机制是一种功能较强的机制,可以用来实现互斥与同步的问题。它只能被两个标准的原语wait(S)和signal(S)访问,也称为P、V操作。
  • PS:原语是指完成某种功能且不被分割、不被中断执行的操作序列,通常可以由硬件来实现。原语功能的不被中断执行特性在单处理机上可由软件通过屏蔽中断方法实现。
  1. 整型信号量
    整型信号量被定义为是一个用于表示资源数目的整型量S,wait和signal操作可描述为:
wait(S){
    while(S <= 0);
    S = S - 1;
}
signal(S){
    S = S + 1;
}
  • 在wait操作中,只要信号量S≤0,就会不断卡在while中不断测试。因此,该机制未遵循“让权等待”的准则,而是让进程处于“忙等”的状态。
  1. 记录型信号量
    记录型信号量是不存在“忙等”现象的进程同步机制。除了需要一个用于代表资源数目的整型变量value外,再增加一个进程链表L,用于链接所有等待该资源的进程。记录型信号量源于采用了记录型的数据结构。记录型信号量可描述为
typedef struct{
    int value;
    struct process *L;
} semaphore;
  • 相应的wait(S)和signal(S)的操作如下:
void wait (semaphore s){ //申请资源
    S.value --;
    if(S.value < 0)}
        把这个进程添加到S.L;
        block(S.L);
    }
}
  • wait操作,S.value --表示进程请求一个该类资源,当S.value<0时,表示该类资源已分配完毕,因此进程应该调用block原语进行自我阻塞,放弃处理机,放弃处理机,并插入该类资源的等待队列S.L。该机制遵循了“让权等待”准则。
void signal(semaphore S){
    S.value++;
    if(S.value<=0){
        从S.L中移除一个进程P;
        唤醒P进程;
    }
}
  • signal操作,表示释放一个资源,使得系统中可供分配该类资源数增1.如果加一后仍value≤0,则表示在S.L中仍有等待该资源的进程呗阻塞,因此还应该调用唤醒原语,将S.L中的第一个等待进程唤醒。
  1. 利用信号量机制实现同步
    信号量机制能用于解决进程间的各种同步问题。设S为实现进程P1,P2同步的公共信号量,初值为0.进程P2中的语句y要使用P1中x的运行结果。所以说只有当P1的x语句执行完毕之后,P2才可以执行y语句。其实现同步的算法如下:
semaphore S = 0;  //初始化信号量
P1(){
    ...
    运行语句x;
    V(S);//S = 1,使得P操作中的while循环跳出执行后续语句,告诉P2,x已完成
    ...
}

P2(){
    ...
    P(S);
    运行语句y;
    ...
}
  • 若P2先执行到P(S)时,S为0,执行P操作会把进程P2阻塞,并放入阻塞队列;当进程P1中的x执行完毕后,把P2从阻塞队列中放回就绪队列,当P2得到处理机时,就继续执行。
  1. 利用信号量机制实现进程互斥
    信号量机制也能很好地解决进程互斥问题。设S为实现进程P1,P2互斥的信号量,由于每次只允许一个进程进入临界区,所以S的初值应该是1,也就是表示可用的资源数为1.现只需把临界区设置于P(S)和V(S)之间,即可实现两个进程对临界资源的互斥访问。其算法如下:
semaphore S = 1; //初始化信号量
P1(){
    ...
    P(S);        //等待准备访问资源
    进程P1的临界区;
    V(S);        //结束访问,解锁临界区
    ...
}
P2(){
    ...
    P(S);
    进程P2的临界区;
    V(S);
    ...
}
  • 分析:当没有进程进入临界区时,任意一个进程要进入临界区,就要执行P操作,把S的值减为0,然后进入临界区;当有进程存在于临界区时,S的值为0,再有进程要想进入临界区时,先执行P操作时将会被阻塞,直至在临界区的进程退出。
  • 总结:在同步问题中,若某个行为要用到某种资源,则在这个行为前面P这种资源一下;若某个行为会提供某种资源,则在这个行为后面V这种资源一下。所以在互斥行为的时候,互斥资源要被PV操作前后包围,中间不能有其他冗余的东西。
  1. 利用信号量机制实现前驱关系
    信号量也可以用来描述程序之间或语句之间的前驱关系,也就是控制程序段执行的顺序。如下所示的一个程序段S1~S6及其前驱图。为了使其能够正确执行,应该设置若干初始值为0的信号量。
    前驱图实例
semaphore a1 = a2 = b1 = b2 = c = d = e = 0;
S1(){
    ...;
    V(a1);V(a2); //S1已完成,释放信号给S2,S3
}
S2(){
    P(a1);       //当S1释放a1后就停止等待,开始执行下面代码
    ...;
    V(b1);V(b2); //S2已完成,释放信号给S4,S5
}
S3(){
    P(a2);       //当S1释放a2后就停止等待,开始执行下面代码
    ...;
    V(c);        //S3已完成,释放信号给S6 
}
S4(){
    P(b1);       //当S2释放b1后就停止等待,开始执行下面代码
    ...;
    V(d)         //S4已完成,释放信号给S6
}
S5(){
    P(b2);       //检查S2是否已经运行完成,当S2释放b2后就停止等待,开始执行下面代码
    ...;
    V(e);        //S5已完成,释放信号给S6
}
S6(){
    P(c);P(d);P(e);//当c,d,e信号都被释放后,开始执行下面代码
    ...;
}
  • 分析:拿S2来说,它是S1的后继,所以要用到S1的资源(信号),前面说在同步问题中,要用某资源就在行为前执行P操作,提供者要执行V操作,就酱。

二、总结
用信号量机制求解同步互斥类问题,可按以下大致思路进行:

  1. 分析关系
    看看问题有多少个进程数目,并分析它们之间的同步和互斥的关系。
  2. 根据进程流程关系确定PV操作的顺序。
  3. 合理设置信号量。设置需要的信号量,确定初始值。
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值