Appearance
2.15 信号量定义
一、整型信号量
最初由Dijkstra把整型信号量定义为一个整型量,除初始化外,仅能通过两个标准的原子操作(Atomic Operation)wait(S)和signal(S)来访问。这两个操作一直被分别称为P、V操作。wait和signal操作可描述为:
P(S): while(S<=0);
S=S-1;
V(S): S=S+1;
面临的问题:只要是信号量S<=0,就会不断地测试。因此,该机制并未遵循"让权等待"的准则。
二、记录型信号量
一个用于代表资源数目的整型变量value
一个进程链表L,用于链接所有等待进程
typedef struct semaphore
{
int value;
List_of_Process L;
}
semaphore S;
P(S):
S.value=S.value-1;
if(S.value<0)
block(S.L);
V(S):
S.value=S.value+1;
if(S.value<=0)
wakeup(S.L);
S.value的初值表示系统中某类资源的数目,因而又称为资源信号量,对它的每次wait操作,意味着进程请求一个单位的该类资源,因此描述为S.value=S.value-1;
。当S.value<0
时,表示该类资源已分配完毕,因此进程应调用block原语,进行自我阻塞,放弃处理机,并插入到信号量链表S.L中。可见,该机制遵循了“让权等待”准则。此时S.value的绝对值表示在该信号量链表中已阻塞进程的数目。
对信号量的每次signal操作,表示执行进程释放一个单位资源,故S.value=S.value+1
操作表示资源数目加1。若加1后仍是S.value<=0
,则表示在该信号量链表中,仍有等待该资源的进程被阻塞,故还应调用wakeup原语,将S.L链表中的第一个等待进程唤醒。 如果S.value的初值为1,表示只允许一个进程访问临界资源,此时的信号量转化为互斥信号量。
三、AND信号量
AND同步机制的基本思想是:将进程在整个运行过程中需要的所有资源,一次性全部地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源,也不分配给他。亦即,对若干个临界资源的分配,采取原子操作方式:要么全部分配到进程,要么一个也不分配。
信号量集
思考:记录型信号量有何不便之处?
- 当一次需要多个资源时,需要进行多次P操作
- 同理,要进行多次释放V操作
如何改进:
// t为下限值,d为需求值
Swait(S[1],t[1],d[1],...,S[n],t[n],d[n])
if(S[1]>=t[1] and ... and S[n]>=t[n])
for(i=1;i<=n;i++)
S[i]=S[i]-d[i];
else
Place the executing process in the waiting queue ofthe first S[i] with S[i]<t[i] and set its program counter to the beginning of the Swait Operation.
signal(S[1],d[1],...,S[n],d[n])
for
{
S[i]=S[i]+d[i];
Remove all the process waiting in the queue associated with S[i] into the ready queue.
}
一般“信号量集”的几种特殊情况
Swait(S, d, d)
:此时在信号量集中只有一个信号量S,但允许它每次申请d个资源,当现有资源数少于d时,不予分配。Swait(S, 1, 1)
:此时的信号量集已退化为一般的记录型信号量(S>1时)或互斥信号量(S=1时)。Swait(S, 1, 0)
:这是一种很特殊且很有用的信号量操作。当S≥1时,允许多个进程进入某特定区;当S变为0后,将阻止任何进程进入特定区。换言之,它相当于一个可控开关。