信号量和pv操作.docx
- 文档编号:25015245
- 上传时间:2023-06-03
- 格式:DOCX
- 页数:18
- 大小:21.72KB
信号量和pv操作.docx
《信号量和pv操作.docx》由会员分享,可在线阅读,更多相关《信号量和pv操作.docx(18页珍藏版)》请在冰豆网上搜索。
信号量和pv操作
在计算机操作系统中,PV操作是进程管理中的难点。
首先应弄清PV操作的含义:
PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
P(S):
①将信号量S的值减1,即S=S-1;
②如果S≥0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):
①将信号量S的值加1,即S=S+1;
②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
PV操作的意义:
我们用信号量及PV操作来实现进程的同步和互斥。
PV操作属于进程的低级通信。
什么是信号量?
信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。
信号量的值与相应资源的使用情况有关。
当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
注意,信号量的值仅能由PV操作来改变。
一般来说,信号量S≥0时,S表示可用资源的数量。
执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。
而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S≤0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
利用信号量和PV操作实现进程互斥的一般模型是:
进程P1 进程P2 …… 进程Pn
…… …… ……
P(S); P(S); P(S);
临界区; 临界区; 临界区;
V(S); V(S); V(S);
…… …… …… ……
其中信号量S用于互斥,初值为1。
使用PV操作实现进程互斥时应该注意的是:
(1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。
若有多个分支,要认真检查其成对性。
(2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
(3)互斥信号量的初值一般为1。
利用信号量和PV操作实现进程同步
PV操作是典型的同步机制之一。
用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。
用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
使用PV操作实现进程同步时应该注意的是:
(1)分析进程间的制约关系,确定信号量种类。
在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
(2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
(3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。
【例1】生产者-消费者问题
在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。
下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。
(1)一个生产者,一个消费者,公用一个缓冲区。
定义两个同步信号量:
empty——表示缓冲区是否为空,初值为1。
full——表示缓冲区中是否为满,初值为0。
生产者进程
while(TRUE){
生产一个产品;
P(empty);
产品送往Buffer;
V(full);
}
消费者进程
while(True){
P(full);
从Buffer取出一个产品;
V(empty);
消费该产品;
}
(2)一个生产者,一个消费者,公用n个环形缓冲区。
定义两个同步信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指
,指向下一个可用的缓冲区。
生产者进程
while(TRUE){
生产一个产品;
P(empty);
产品送往buffer(in);
in=(in+1)modn;
V(full);
}
消费者进程
while(TRUE){
P(full);
从buffer(out)中取出产品;
out=(out+1)modn;
V(empty);
消费该产品;
}
(3)一组生产者,一组消费者,公用n个环形缓冲区
在这个问题中,不仅生产者与消费者之间要同步,而且各个生产者之间、各个消费者之间还必须互斥地访问缓冲区。
定义四个信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。
设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。
生产者进程
while(TRUE){
生产一个产品;
P(empty);
P(mutex1);
产品送往buffer(in);
in=(in+1)modn;
V(mutex1);
V(full);
}
消费者进程
while(TRUE){
P(full)
P(mutex2);
从buffer(out)中取出产品;
out=(out+1)modn;
V(mutex2);
V(empty);
消费该产品;
}
需要注意的是无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒。
应先执行同步信号量的P操作,然后再执行互斥信号量的P操作,否则可能造成进程死锁。
【例2】桌上有一空盘,允许存放一只水果。
爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。
规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发进程的同步。
分析 在本题中,爸爸、儿子、女儿共用一个盘子,盘中一次只能放一个水果。
当盘子为空时,爸爸可将一个水果放入果盘中。
若放入果盘中的是桔子,则允许儿子吃,女儿必须等待;若放入果盘中的是苹果,则允许女儿吃,儿子必须等待。
本题实际上是生产者-消费者问题的一种变形。
这里,生产者放入缓冲区的产品有两类,消费者也有两类,每类消费者只消费其中固定的一类产品。
解:
在本题中,应设置三个信号量S、So、Sa,信号量S表示盘子是否为空,其初值为l;信号量So表示盘中是否有桔子,其初值为0;信号量Sa表示盘中是否有苹果,其初值为0。
同步描述如下:
intS=1;
intSa=0;
intSo=0;
main()
{
cobegin
father(); /*父亲进程*/
son(); /*儿子进程*/
daughter(); /*女儿进程*/
coend
}
father()
{
while
(1)
{
P(S);
将水果放入盘中;
if(放入的是桔子)V(So);
else V(Sa);
}
}
son()
{
while
(1)
{
P(So);
从盘中取出桔子;
V(S);
吃桔子;
}
}
daughter()
{
while
(1)
{
P(Sa);
从盘中取出苹果;
V(S);
吃苹果;
}
}
思考题:
四个进程A、B、C、D都要读一个共享文件F,系统允许多个进程同时读文件F。
但限制是进程A和进程C不能同时读文件F,进程B和进程D也不能同时读文件F。
为了使这四个进程并发执行时能按系统要求使用文件,现用PV操作进行管理,请回答下面的问题:
(1)应定义的信号量及初值:
。
(2)在下列的程序中填上适当的P、V操作,以保证它们能正确并发工作:
A() B() C() D()
{ { { {
[1]; [3]; [5]; [7];
readF; readF; readF; readF;
[2]; [4]; [6]; [8];
} } } }
思考题解答:
(1)定义二个信号量S1、S2,初值均为1,即:
S1=1,S2=1。
其中进程A和C使用信号量S1,进程B和D使用信号量S2。
(2)从[1]到[8]分别为:
P(S1)V(S1)P(S2)V(S2)P(S1)V(S1)P(S2)V(S2)
具体PV原语对信号量的操作可以分为三种情况:
1) 把信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。
实现过程:
P(mutex); //mutex的初始值为1
访问该共享数据;
V(mutex);
非临界区
2) 把信号量视为是某种类型的共享资源的剩余个数,实现对一类共享资源的访问。
实现过程:
P(resource); //resource的初始值为该资源的个数N
使用该资源;
V(resource);
非临界区
3) 把信号量作为进程间的同步工具
实现过程:
临界区C1; P(S);
V(S); 临界区C2;
下面用几个例子来具体说明:
例1:
某超市门口为顾客准备了100辆手推车,每位顾客在进去买东西时取一辆推车,在买完东西结完帐以后再把推车还回去。
试用P、V操作正确实现顾客进程的同步互斥关系。
分析:
把手推车视为某种资源,每个顾客为一个要互斥访问该资源的进程。
因此这个例子为PV原语的第二种应用类型。
解:
semaphore S_CartNum; // 空闲的手推车数量, 初值为100
void consumer(void) // 顾客进程
{
P(S_CartNum);
买东西;
结帐;
V(S_CartNum);
}
例2:
桌子上有一个水果盘,每一次可以往里面放入一个水果。
爸爸专向盘子中放苹果,儿子专等吃盘子中的苹果。
把爸爸、儿子看作二个进程,试用P、V操作使这四个进程能正确地并发执行。
分析:
爸爸和儿子两个进程相互制约,爸爸进程执行完即往盘中放入苹果后,儿子进程才能执行即吃苹果。
因此该问题为进程间的同步问题。
解:
semaphore S_PlateNum; // 盘子容量,初值为1
semaphore S_AppleNum; // 苹果数量,初值为0
void father() // 父亲进程
{
while
(1)
{
P(S_PlateNum);
往盘子中放入一个苹果;
V(S_AppleNum);
}
}
void son() // 儿子进程
{
while
(1)
{
P(S_AppleNum);
从盘中取出苹果;
V(S_PlateNum);
吃苹果;
}
}
另附用PV原语解决进程同步与互斥问题的例子:
经典IPC问题如:
生产者-消费者,读者-写者,哲学家就餐,睡着的理发师等可参考相关教材。
一、两个进程PA、PB通过两个FIFO(先进先出)缓冲区队列连接(如图)
PA
PB
Q1
Q2
PA从Q2取消息,处理后往Q1发消息,PB从Q1取消息,处理后往Q2发消息,每个缓冲区长度等于传送消息长度.Q1队列长度为n,Q2队列长度为m. 假设开始时Q1中装满了消息,试用P、V操作解决上述进程间通讯问题。
解:
//Q1队列当中的空闲缓冲区个数,初值为0
semaphore S_BuffNum_Q1;
//Q2队列当中的空闲缓冲区个数,初值为m
semaphore S_BuffNum_Q2;
//Q1队列当中的消息数量,初值为n
semaphore S_MessageNum_Q1;
//Q2队列当中的消息数量,初值为0
semaphore S_MessageNum_Q2;
void PA()
{
while
(1)
{
P(S_MessageNum_Q2);
从Q2当中取出一条消息;
V(S_BuffNum_Q2);
处理消息;
生成新的消息;
P(S_BuffNum_Q1);
把该消息发送到Q1当中;
V(S_MessageNum_Q1);
}
}
void PB()
{
while
(1)
{
P(S_MessageNum_Q1);
从Q1当中取出一条消息;
V(S_BuffNum_Q1);
处理消息;
生成新的消息;
P(S_BuffNum_Q2);
把该消息发送到Q2当中;
V(S_MessageNum_Q2);
}
}
二、《操作系统》课程的期末考试即将举行,假设把学生和监考老师都看作进程,学生有N人,教师1人。
考场门口每次只能进出一个人,进考场的原则是先来先进。
当N个学生都进入了考场后,教师才能发卷子。
学生交卷后即可离开考场,而教师要等收上来全部卷子并封装卷子后才能离开考场。
(1)问共需设置几个进程?
(2)请用P、V操作解决上述问题中的同步和互斥关系。
解:
semaphore S_Door; // 能否进出门,初值1
semaphore S_StudentReady; // 学生是否到齐,初值为0
semaphore S_ExamBegin; // 开始考试,初值为0
semaphore S_ExamOver; // 考试结束,初值为0
int nStudentNum=0; // 学生数目
semaphore S_Mutex1 //互斥信号量,初值为1
int nPaperNum=0; // 已交的卷子数目
semaphore S_Mutex2 //互斥信号量,初值为1
void student()
{
P(S_Door);
进门;
V(S_Door);
P(S_Mutex1);
nStudentNum++; // 增加学生的个数
if(nStudentNum==N) V(S_StudentReady);
V(S_Mutex1);
P(S_ExamBegin); // 等老师宣布考试开始
考试中…
交卷;
P(S_Mutex2);
nPaperNum++; // 增加试卷的份数
if(nPaperNum==N) V(S_ExamOver);
V(S_Mutex2);
P(S_Door);
出门;
V(S_Door);
}
void teacher()
{
P(S_Door);
进门;
V(S_Door);
P(S_StudentReady);//等待最后一个学生来唤醒
发卷子;
for(i=1;i<=N;i++) V(S_ExamBegin);
P(S_ExamOver); // 等待考试结束
封装试卷;
P(S_Door);
出门;
V(S_Door);
}
三、某商店有两种食品A和B,最大数量均为m个。
该商店将A、B两种食品搭配出售,每次各取一个。
为避免食品变质,遵循先到食品先出售的原则。
有两个食品公司分别不断地供应A、B两种食品(每次一个)。
为保证正常销售,当某种食品的数量比另一种的数量超过k(k break-word;">个时,暂停对数量大的食品进货,补充数量少的食品。 (1) 问共需设置几个进程? (2) 用P、V操作解决上述问题中的同步互斥关系。 解: semaphore S_BuffNum_A; //A的缓冲区个数, 初值m semaphore S_Num_A; //A的个数,初值为0 semaphore S_BuffNum_B; //B的缓冲区个数, 初值m semaphore S_Num_B; //B的个数,初值为0 void Shop() { while (1) { P(S_Num_A); P(S_Num_B); 分别取出A、B食品各一个; V(S_BuffNum_A); V(S_BuffNum_A); 搭配地销售这一对食品; } } //“A食品加1,而B食品不变”这种情形允许出现的次数(许可证的数量),其值等于//k-(A-B),初值为k semaphore S_A_B; //“B食品加1,而A食品不变”这种情形允许出现的次数(许可证的数量),其值等于//k-(B-A),初值为k semaphore S_B_A; void Producer_A() { while (1) { 生产一个A食品; P(S_BuffNum_A); P(S_A_B); 向商店提供一个A食品; V(S_Num_A); V(S_B_A); } } void Producer_B() { while (1) { 生产一个B食品; P(S_BuffNum_B); P(S_B_A); 向商店提供一个B食品; V(S_Num_B); V(S_A_B); } } 四: 在一栋学生公寓里,只有一间浴室,而且这间浴室非常小,每一次只能容纳一个人。 公寓里既住着男生也住着女生,他们不得不分享这间浴室。 因此,楼长制定了以下的浴室使用规则: (1)每一次只能有一个人在使用; (2)女生的优先级要高于男生,即如果同时有男生和女生在等待使用浴室,则女生优先;(3)对于相同性别的人来说,采用先来先使用的原则。 假设: (1)当一个男生想要使用浴室时,他会去执行一个函数boy_wants_to_use_bathroom,当他离开浴室时,也会去执行另外一个函数boy_leaves_bathroom; (2)当一个女生想要使用浴室时,会去执行函数girl_wants_to_use_bathroom,当她离开时, 也会执行函数girl_leaves_bathroom; 问题: 请用信号量和P、V操作来实现这四个函数(初始状态: 浴室是空的)。 解: 信号量的定义: semaphore S_mutex; // 互斥信号量,初值均
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 信号量 pv 操作