操作系统之信号量机制总结

  1965年,荷兰学者Djikstra提出信号量(Semaphores)机制是一种卓有成效的进程同步工具。在长期的应用中,信号量机制又获得了很大的发展,从整型信号量记录型信号量,进而发展成“信号量集”机制,下面我们来讨论一下各种信号量机制的内容。

1、整形信号量(经典的PV操作:P(wait):申请资源 V(signal):释放资源)

1 wait(S):while S<=0 do no-op;
2     S:=S-1;
3 signal(S):  S:=S+1

2、记录型信号量

在整形信号量机制中的wait操作,只要是信号量S≤0,就会不断测试。该机制并未遵守“让权等待”的准则,而是使进程处于“忙等”的状态。

在记录型信号量是一种不存在“忙等”现象的进程同步机制。但是采取了“让权等待”的策略后又会出现多个进程等待访问同一临界资源的情况。为此,在信号量机制中出了一个需要用于表示资源数目的整形变量value外,还应增加一个进程链表指针L,用于链接上述所有等待进程。

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

3、AND型信号量

       前面讨论的进程互斥问题都是共享一个临界资源而言的,但是在很多情况下一个进程需要获得两个或多个共享资源后才能执行其任务。如果此类问题利用上述办法将会陷入死锁状态。

       AND同步机制的基本思想:将进程在整个运行过程中需要的所有资源一次性全部分配给进程,待进程用完后再一起释放。只要尚有一个资源未分配给进程,其他所有可能为之分配的资源也不分配给它。亦即,对若干个临界资源的分配采取原子操作方式:要么把它所请求的资源全部分配给进程,要么一个也不分配。由死锁理论可知,可避免死锁的发生。

 1 Swait(S1,S2,...,Sn)
 2     if Si>=1 and ... and Sn>=1 then
 3         for i:=1 to n do
 4         Si:=Si-1;
 5         endfor
 6     else
 7         place the process in the waiting queue associated with the first Si found with Si<1,and set the program count of this process to the begining of Swait operation
 8     endif
 9 Ssignal(S1,S2,...,Sn)
10     for i:=1 to n do
11         Si = Si+1;
12     Remove all the process waiting in the queue associated with Si into the ready queue.
13     endfor;

 

4、信号量集:

       在记录性信号量机制中,wait(S)或signal(S)操作仅能对信号量施以加1或减1操作,意味着每次只能获得或释放一个单位的临界资源。而当一次需要N个某类临界资源时便需要进行N次操作,显然这是低效的。此外在一些情况下,当资源数量低于某一下限值时,便不予以分配。因而在每次分配之前,都必须测试该资源的数目,看其是否大于其下限值。基于以上两点,对AND型信号量加以扩充,行成一般化的“信号量集”机制。

Swait操作描述如下:

S:信号量 d:需求值 t:下限值

 

 1 Swait(S1,t1,d1,...,Sn,tn,dn)
 2     if S1>=t1 and ... and Sn >- tn then  // 每种信号量大于下限值
 3         for i:=1 to n do
 4             Si:=Si - di;                 // 分配进程所需求的资源(信号量减去相应的需求值为剩余信号量的数量)
 5         endfor
 6     else
 7     Place the executing process in the waiting queue of the first Si with Si<ti and set its program counter to the begining of the Swait operation.
 8     endif
 9 Ssignal(S1,d1,...,Sn,dn)
10     for i:=1 to n do
11         Si:=Si+di;     // 释放资源
12     Remove all the process waiting in the queue associated with Si into the ready queue
13     endfor

 

下面讨论一般“信号量集”的几种特殊的情况:

(1)Swait(S,d,d):此时信号量集中只有一个信号量S,但允许每次申请d个资源,当现有资源少于d时,不予分配

(2)Swait(S,d,d):此时信号量集已退化为一般的记录型信号量(S>1)或互斥信号量(S=1时)

(3)Swait(S,1,0):这是一种很特殊且很有用的信号量操作。当S≥1时,允许多个进程进入某特定区;当S变为0后将阻止任何进程进入特定区,换言之,它相当于一个可控开关。

posted @ 2018-08-12 20:27  JiangXiaoKun  阅读(6495)  评论(0编辑  收藏