本站动态:

第三章: 进程同步机制

第三章: 进程同步机制

3.1 信号量和P、V操作

信号量:表示资源使用情况的一种数据结构

struct{
	int n; //正数表示当前可用的资源个数,负数表示等待该种资源的进程个数
	PCB* pcbList; //等待该种资源的进程(PCB)列表
}

信号量的值仅由P、V操作来改变

原语:机器指令的延生,往往是为完成某些特定功能而编制的一段系统程序,其操作具有不可分割性(一次性完成)

P操作P(S):也叫wait操作,S为相应的信号量

S = S - 1;
if (S < 0)
{
    //资源不足,得不到分配的情况
    将本进程链入 S 的队尾;
    阻塞本进程;
}
else
{
    本进程继续执行;
}

V操作V(S): 也叫signal操作

S = S + 1;
if (S > 0)
{
    //说明目前没有进场在等待该资源
    本进程继续执行;
}
else
{
    //说明有进程在等待该资源
    释放S队列上的第一个PCB;
    本进程继续执行;
}

3.2 同步机制的应用

使用PV操作实现进程互斥

  • 在每个进程中,P(mutex)和V(mutex)必须成对出现,并且先P后V
  • 互斥信号量mutex的初值一般为1

使用PV操作实现简单同步

例如 : 供者和用者共同使用缓冲区的问题

分析和解答:供者和用者两个需要合作来完成,它们之间的桥梁是缓冲区,它们之间的动作需要按照一定的先后顺序才能顺利进行,它们之间的关系是同步。临界资源是缓冲区,因为供者在向缓冲区写入数据的时候,用者不能从缓冲区读数据,同样,在缓冲区数据写满后,用者开始读缓冲区数据,这时供者不能往缓冲区里写数据,直到用者从缓冲区中取完数据。缓冲区有两个临界状态,一是空了,一是满了。使用两个信号量来表示,E表示空了的状态,F表示满了的状态,初始状态下缓冲区是空着的,所以E = 1, F = 0。对于供者,先用P操作获得空着的缓冲区,在写满数据之后,再用V操作释放一个满了的缓冲区的信号量;而用者则使用P操作获得写满的缓冲区,在取完数据之后,再用V操作释放清空的缓冲区的信号量。 所以供者的程序如下:
P(E);
写数据到缓冲区;
V(F);
用者的程序如下:
P(F);
将缓冲区中的数据全部取走;
V(E);

不难理解为什么P操作又叫wait操作,而V操作又叫signal操作。因为P操作会确保获得满足信号量要求的临界资源,如果暂时没有,会等待直到其他进程释放出该临界资源并得到后再继续执行;V操作会释放出一种临界资源,发出一个信号,如果有其他进程在等待该资源,会将该资源交给队列最前面的那个进程。

这里有个比较容易混淆的问题:既然临界资源只有缓冲区一种,为什么使用两个信号量E和F?回顾一下什么是信号量,信号量并不代表临界资源,而是临界资源的状态,既然临界资源有两种状态空着和满了,就可以用两个信号量来表示。另外初始值E = 1表示有一个空着的缓冲区,而不是表示缓冲区是空着的,F = 0 表示没有满了的缓冲区,而不是表示缓冲区没有满(或者是空着的)。

使用PV操作的说明:

  • 确定彼此关系和信号量种类
  • 设定信号量初值
  • 同一信号量的PV操作要成对出现,只是互斥的PV操作在同一进程中成对出现,而同步的PV操作在不同进程中成对出现。

同步互斥的经典例子:生产者和消费者

生产者和消费者的问题和上面提到的供着和用者的例子类似,只是供着和用者只有一个缓冲区,而生产者和消费者有N个缓冲区,构成缓冲池。当N=1时候,本问题就成为了供者和用者的问题,可见,供者和用者的问题只是本问题的一个特例而已。

1、消费者只有在生产者生产出产品之后才能消费(缓冲池中有满的缓冲区时才可以让消费者从缓冲区取走产品消费)
2、生产者在缓冲池满了以后要暂停生产,直到有空的缓冲区出现
3、为避免混乱,生产者和消费者互斥使用缓冲池

上面的1、2点讲的就是供者和用者中提到的同步问题,第3点讲的是互斥问题。

同步问题同样设E和F两个信号量,E表示缓冲池中空缓冲区的数目,初始状态下E = 0; F表示缓冲池中满了的缓冲区的个数,初始状态下F = N。另外增加缓冲池的互斥信号量M, 初始状态下M = 1(表示只用一个缓冲池可供使用)

对于生产者,他要做的事情是:1、等待获得空缓冲区;2、等待获得缓冲池的使用权;3、往空缓冲区中放入产品;4、释放缓冲池使用权(通知缓冲池可以使用了);5、通知新增一个满的缓冲区(一个新产品)

对于消费者,他要做的事情是:1、等待获得满的缓冲区;2、等待获得缓冲池的使用权;3、从满的缓冲区中取走产品;4、释放缓冲池使用权(通知缓冲池可以使用了);5、通知新增一个空的缓冲区

生产者和消费者都要做5步动作,其中他们的第4步和第5步都是可以互换的,但是其他步骤是不能改变顺序的,尤其是第一步和第二步。如果第一步和第二步颠倒,很可能发生锁住的问题(死锁),导致生产者和消费者都不能往下进行。举个例子:假如消费者先获得了缓冲池的使用权,然后等待获得满的缓冲区,不过当时没有满的缓冲区,它就在一直占用缓冲池的情况下处于等待状态;而生产者因为得不到缓冲池的使用权,也无法让缓冲区变慢,这样消费者也就永远无法获得满的缓冲区(产品),于是生产者和消费者谁也干不了活了。不过有个原则是:互斥信号量的PV操作要成对出现在临界区的前后,所以第4步和第5步最好不要颠倒,既便于记忆,又避免出错。

上面的步骤中凡是使用了”等待获得“来描述的,都是P操作,要获得的东西是P操作的信号量;凡是用到了”释放“或”通知“的步骤都是V操作,释放或通知的东西就是V操作的信号量。

注意:

  • P(mutex)和V(mutex)分别出现在临界区的前后
  • 各信号量的P、V操作都要成对出现
  • 两个P操作的顺序不能颠倒


[本日志由 shosh 于 2009-11-15 02:55 AM 编辑]
文章来自: Shosh原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
相关日志:
评论: 0 | 引用: 0 | 查看次数: 762
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭