并发编程之信号量机制

百度百科:信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。

一、信号量机制包含以下几个核心概念:

1、信号量S,整型变量,需要初始化值大于0
2、P原语,荷兰语Prolaag(probeer te verlagen),表示减少信号量,该操作必须是原子的
3、V原语,荷兰语Verhogen,表示增加信号量,该操作必须是原子的

“原子操作(atomic operation)是不需要synchronized”,这是多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何context switch (切换到另一个线程)。如下图的wait()和signal()

在这里插入图片描述

二、P和V操作:
信号灯是一个确定的二元组(s,q),s是一个具有非负初值的整型变量,q是一个初始状态为空的队列。s代表资源实体或并发进程的状态,操作系统利用信号灯的状态对并发进程和共享资源进行管理。

当信号灯的值s大于或等于0时,表示绿灯,进程可以继续推进;若信号灯的值s小于0时,表示红灯,进程被阻。

P操作
1、s值减1
2、若相减结果大于或等于0,则进程继续执行
3、若相减结果小于0,则进程封锁,并将它插入到该信号灯的等待队列中,然后转进程调度程序

V操作
1、s值加1
2、若相加结果大于0,则进程继续执行
3、若相加结果小于或等于0,则从该信号灯的等待队列中移除一个进程,解除它的等待状态,然后返回本进程继续执行。

信号灯是操作系统实现进程间同步和通信的一种常用工具
同步机制应遵循的准则
(1)空闲让进 当无进程处于临界区时,应允许一个请求进入临界区的进程进入临界区;
(2)忙则等待 当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
(3)有限等待 对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入“死等”状态;
(4)让权等待 当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入“忙等”。

三、信号量分类
信号量可分为四类:整型信号量,纪录型信号量,AND型信号量,信号量集

1、整型信号量

var S interger;
    wait(S)//申请资源
    {
         while S <= 0 do no - op
         S = S - 1;
    }
    signal(S)//释放资源
    {
        S = S + 1;
    }

2、纪录型信号量
在整形信号量机制中的wait操作,只要是信号量S≤0,就会不断测试。该机制并未遵守“让权等待”的准则,而是使进程处于“忙等”的状态。
在记录型信号量是一种不存在“忙等”现象的进程同步机制。但是采取了“让权等待”的策略后又会出现多个进程等待访问同一临界资源的情况。为此,在信号量机制中出了一个需要用于表示资源数目的整形变量value外,还应增加一个进程链表指针L,用于链接上述所有等待进程。

type semapthere = record // 信号量类型 记录型
    value:integer;       // 资源数目
    L:list of process    // 进程链表指针
    end
//P、V操作如下:
procedure wait(S)
    var S:semapthere;    // 声明一个记录型信号量 包含value和L
    begin
        S.value:=S.value-1              // 申请一个资源,资源数目少一个
        if S.value<0 then block(S.L);   // 如果资源数目小于0,说明该类资源分配完毕,调用block原语,进行自我阻塞,放弃处理机。然后将当前进程插入到信号量链表中,此时S.value的绝对值表示该信号量链表中阻塞进程的数目。
    end
procedure signal(S)
    var S:semapthere;
    begin
        S.value:=S.value+1;             // 释放一个单位资源,资源数目加1
        if S.value<=0 then wakeup(S.L); // 如果资源数目小于0(加1后),表示仍然有进程处于阻塞状态,调用wakeup原语将S.L中第一个等待的进程唤醒。
    end

3、AND型信号量
基本思想:将进程在整个运行过程中所需要的所有资源一次性地全部分配给进程,待进程使用完后再一起释放。只要还有一个资源不能分配给该进程,其他所有可能为之分配的资源也不能分配给它。即:对若干个临界资源的分配采取原子操作方式,要么把它所请求的资源全部分配给进程,要么一个也不分配。避免死锁的发生

Swait(S1,S2,...,Sn)
    if Si>=1 and ... and Sn>=1 then
        for i:=1 to n do
        Si:=Si-1;
        endfor
    else
	//把进程插入Si阻塞队列中,并把程序计数器的值赋值为Swait的起始地址
Ssignal(S1,S2,...,Sn)
    for i:=1 to n do
        Si = Si+1;
	//将阻塞在Si队列中的进程唤醒,插入就绪队列
 endfor;

4、信号量集
思想:若进程一次需要申请多类临界资源,则在进行临界资源分配时,先测试各类临界资源是否大于其下限值。若低于下限值,则不予分配。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值