信号量的原理总结

来源:互联网 发布:海信高清网络机顶盒 编辑:程序博客网 时间:2024/06/10 03:18

谈到信号量,大多数会立马想到PV操作,这个用荷兰语表示的专有名词。

对比前面我们说的,四种实现临界区互斥的软件设计算法,PV操作更加的优良,现在这里就将对其原理进行详细的解释分析,以及如何在题目的场景中使用,包括算法的设计和问题的分析。

http://blog.csdn.net/u011240016/article/details/52628467

首先,信号量机制我们着重谈两个设计思路,核心相同,设计有细微的差别,但不要被名称所迷惑。
它们是:

  • 整形信号量
  • 记录型信号量

整形信号量

整形信号量表示的是资源的数目S。P操作将减少一个资源,V操作将增加一个资源(即释放一个资源,因为资源不会被操作生出来,只会因别人不用而释放)。
这里不用wait和signa这种看着含义更加明显的名词,是因为,P、V可以这么联想:一个进程想利用资源了,就拍拍手,表达自己的意愿,这样就可以将S-1,而当自己用好了,就表示一个V字手势,表示成功了,资源可以收回去了。

void P(S){    S--;}void V(S){    S++;}

所以,我更加倾向于用PV直接表达PV操作。因为这个图像更加生动。当然,用wait和signal,as you wish, 你开心就好。

我想强调的有一个点在于:S的边界含义,当然S > 0和S < 0的时候都很自然。

问,S = 0时候表示什么意思?

既然S是可用资源的数目,那么S = 0,表示已经没有资源可用了。

在整型信号量中,只要S <= 0,就会不断测试,看何时有资源可用。

也因此,进程会一直等,不遵循让权等待的原则。

更好的做法是,像我们在进程调度中学到的,加一个就绪队列。
也即,引入:记录型信号量。

记录型信号量
我们常说这个算法是一种进程同步机制,而不说是互斥机制。
是因为,使用PV的思路进行进程的互斥访问,非常简单,只需要设置一个mutex,取值仅仅为0或者1即可。而同步的话就复杂一些,采用用到这个记录型信号量。

首先看semaphore的设计:

typedef struct {    int value;    struct process *L;} semaphore;

这里的value和上面的S含义相同,都表示可用的资源数目。

链表L表示的是就绪队列,因此核心仍是PV,只不过如何对待进程,记录型信号量的做法更加完善。解决了让进程忙等的现象。

void P(semaphore s){    s.value--; // 申请资源,边界是value已经为0了,那么现在变-1,表示有一个进程在等待    if(s.value < 0)    {        将此进程加入就绪队列,等待;        block(s.L);    }}void V(semaphore s){    s.value++;    if(s.value <= 0)    {        将进程P从就绪队列中移出;        wakeup(P);// 叫醒P,让它起来干活    }}

这里有意思的是,在V的时候,边界为啥是s.value <= 0.

当s.value = 0时,是从s.value = -1时候变过来的,因此,虽然s.value = 0了,还不能忘了把最后一个进程移出就绪队列并叫醒它。

s.value小于等于0时,绝对值表示的是等待进程的数目。
还需要注意s.value++的时机。如果设计算法时,先判断再加,则s.value < 0即可:

void V(semaphore s){    if(s.value < 0)    {        将进程P从就绪队列中移出;        wakeup(P);// 叫醒P,让它起来干活    }    s.value++;}

所以,算法背后是思想,需要仔细体会才能领悟。

以上。

0 0
原创粉丝点击