四、信号量
信号量是一种功能十分强大的原语,可以用于解决进程的互斥、同步问题,且都是理想的解决方案。
————
1、信号量的原理
整型信号量:简单情况下,信号量是一个特殊的整型变量,一般用于描述资源的个数,因此通常初始化为一个非负整数,初始化后,只能被两个特殊操作,Up和Down使用,通常被称为整型信号量。
记录型信号量:在整型信号量的基础上,若S是一个记录型信号量,它包含以下两个分量:
value:表示为S.value,与整型信号量含义用途相同
queue:表示为S.queue,是一个进程队列处初值为空用于记录因等待该资源而进入阻塞的进程。
两个操作:
若S是一个信号量
Up:记为Up(S),其中包含以下两个不可分割的操作:①S.value=S.value+1,意为释放一个资源(资源个数加一);②若S.value>0,进程或线程继续执行;否则S.value小于或等于0,唤醒S.queue中第一个进程或线程,后返回原进程继续执行。
例:一个进程在使用A资源,S.value表示空闲的A资源的个数,该进程使用完后,释放A资源,则可用数+1,如果+1后,可以变为空闲状态的A资源还是小于0,说明该进程用完后,还有其他进程需要用到A,就将要用到A资源的进程唤醒。
Down操作:记为Down(S),包含两个不可分割的操作:①S.value=S.value-1,意为要求系统给这个进程分配一个该资源,因此可用数-1。②若S.value>=0,继续执行,若小于0,该进程阻塞并插入到等待队列S.queue。
——————
一些其他类型的信号量:
按取值分类:
二元信号量:进允许信号量取值为0或1,主要解决进程互斥问题。
一般信号量:允许初值为非负整数,解决进程同步问题。
按用途分类:
私有信号量:多用于并发进程的同步,初值常为非负整数。
共有信号量:多用于并发进程的互斥,初值常为1。
——————
2、用信号量实现进程互斥
为临界资源设置信号量初值为1,将临界代码置于Down(S)和Up(S)之间,就能实现进程的互斥。同时避免了忙等待的问题。
——————
3、用信号量实现进程的同步
若有两个进程,进程1和进程2,进程1有语句S1,进程2有语句S2,只有S1执行后,S2才能被执行,那么可以设置一个公共信号量S,初值为0.在执行S2之前必须执行Down(S),执行S1之后必须执行Up(S),这样,只有S1被执行之后,S=S+1,Down(S)才能被执行,即S2才能执行。
——————
4、信号量解决生产者-消费者问题
该问题存在三个子问题:①缓冲区有消息,消费者才能取走;②缓冲区未满,生产者才能放入;③缓冲区这一临界资源,生产者和消费者不能同时访问
①②涉及同步问题,③涉及互斥问题。
同步角度需要设置两个信号量:full,表示缓冲区的产品数量,初值为0,empty,表示缓冲区剩余单元数,初值为缓冲区大小。
互斥角度设置一个初值为1的信号量。
实现同步和互斥的具体方法参考2和3中的思路。