一、信号量(Semaphore)的概念
1. 信号量的定义
除初始化外,仅能由同步原语对其进行操作的整型变量。
2. 信号量的分类
整型信号量、记录型信号量、AND型信号量、信号量集
按照用途分类,又可分为两大类:
二元信号量:用作互斥变量,初值为1
一般信号量:用于一般同步,初值为共享资源的初始数量
二、整型信号量
1. 整型信号量的定义
除初始化外,仅能通过两个标准的原子操作 wait(S) 和 siganl(S) 访问的整型变量S。用于表示资源数目。
2. 同步原语
为什么又叫做P、V操作呢?因为是它们是“测试”和“增加”的荷兰语首字母。
P、V操作是两个原子操作,因此,在执行过程中是不可中断的。
P() / wait () :测试资源数量(即信号量S)是否大于0
V() / signal () :使资源数量(即信号量S)加一,表示执行进程释放一个单位的资源
wait () 操作可描述如下:
wait( S ) {
while( S<=0 )
; // 如果S一直<=0,就是一个死循环,一直不断地测试(查询)资源情况,等待着
S- -; // 出循环了,说明有资源可以用了,那么资源数减一
}
signal () 操作可描述如下:
signal( S ) {
S++;
}
三、记录型信号量(资源信号量)
对整型信号量的缺陷做出了改进:
整型信号量机制的 wait 操作中,只要信号量S<=0,就会一直测试。因此,该机制并没有遵循“让权等待”的原则(不知道什么是让权等待的可以去看我的【OS笔记 14】),而是处于忙等状态。
记录型信号量则克服了“忙等”,下面来讲解:
1. 记录型信号量的组成
① 用于表示资源数目的整型变量 value (但是这里可以是负数,比如 value = -5,表示已经有5个进程在等待该资源了)
② 进程链表指针 list,用于链接所有正在等待资源的进程
2. wait 和 signal 操作的描述
其中,block()原语是进程用来自我阻塞的,也就是放弃了处理机,这样也就避免了忙等。
举个例子来讲一下具体过程,更好理解:
value 初值为5。接下来依次有五个进程 ABCDE 各使用了一个资源,那么此时value = 0。
现在又来了两个进程 FG,各请求了一个资源,那么此时 value = -2,这两个进程都处于阻塞态。
A首先使用完毕,释放了资源,调用 signal 操作,value++之后变成 -1,然后从阻塞链表中取出头部的那个进程F,使用 wakeup() 原语把它唤醒。
然后B释放资源,value变成0,value<=0 说明还有进程在阻塞,继续唤醒G。
然后C释放资源,value变成1,说明已经没有阻塞的进程了,不需要唤醒。