操作系统pv操作学习总结

PV操作

PV操作与信号量的处理相关,P表示通过的意思,V表示释放的意思。


目录
1 简介
2 详细资料
3 解释
▪ 信号量的概念
▪ 典型理解偏差
简介
1962年,狄克斯特拉离开数学中心进入位于荷兰南部的艾恩德霍芬技术大学(Eindhoven Technical University)任数学教授。在这里,他参加了X86计算机的开发,设计与实现了具有多道程序运行能力的操作系统——THE Multiprogramming System。
详细资料
THE 是艾恩德霍芬技术大学的荷兰文Tchnische Hoogeschool Eindhov –en的词 头缩写。狄克斯特拉在THE这个系统中所提 出的一系统方法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样一些重要的思想和概念都是狄克斯特拉在THE中首先提出并为以后的操作系统如UNⅨ等所采用的。
为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运行”(running)和“阻塞”(blocking)三个工作 状态。由于在任一时刻最多只有一个进程可以使用处理机,正占用着处理机的进程称为“运行”进程。当某进程已具备了使用处理机的条 件,而当前又没有处理机供其使用,则使该进程处于“就绪”状态。当运行进程由于某种原因无法继续运行下去时,就停止其占用处理机,使之进入“阻塞”状态,待造成其退出运行的条件解除,再进入“就绪”状态。而对系统中所有同时运行的进程之间所存在的相互制约的同步(synchronization,指为了避免错误,在一个进程访问共享数据时,另一个进程不访问该数据)和互斥(mutually-exclusive,指两个进程不能同时在一个临界区中使用同一个可重复使用的资源,诸如读写缓冲区)两个关系,狄克斯特拉巧妙地利用火车运行控制系统中的“信号灯”(semaphore,或叫“信号量”)概念加以解决。
所谓信号灯,实际上就是用来控制进程状态的一个代表某一资源的存储单元。例如,P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程,为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”,P操作和V操作是执行时不被打断的两个操作系统原语。执行P操作P(S)时信号量S的值减1,若结果不为负则P(S)执行完毕,否则执行P操作的进程暂停以等待释 放。执行V操作V(S)时,S的值加1,若结果不大于0则释放一个因执行P(S)而等待的进程。对P1和P2可定义两 个信号量S1和S2,初 值分别为1和0。进程P1在向缓冲B送入数据前执行P操 作P(S1),在送入数据后执行V操 作V(S2)。进程P2在从缓冲B读取数 据前先执行P操作P(S2),在读出数据 后执行V操作V(S1)。当P 1往缓冲B送入一数据后信号量S1之值变为0,在该数据读出后S1之值才又变为1,因此在前一数未读出前 后一数不会送入,从而保 证了P1和P2之间的同步。
中国读者常常不明白这一同步机制为什么叫PV操作,原 来这是狄克斯特拉用荷兰文定义的,因为在荷 兰文中,通过叫passeren,释放叫vrijgeven,PV操 作因此得名。这是在计算机术语中不是用英 语表达的极少数的例子之一。
解释
1962年,狄克斯特拉离开数学中心进入位于荷兰南部的艾恩德霍芬技术大学(EindhovenTechnical University)任数学教授。在这里,他参加了X8计算机的开发,设计与实现了具有多道程序运行能力的操作系统——THE Multiprogramming System。THE是艾恩德霍芬技术大学的荷兰文Tchnische Hoogeschool Eindhov –en的词头缩写。狄克斯特拉在THE这个系统中所提出的一系统方法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样一些重要的思想和概念都是狄克斯特拉在THE中首先提出并为以后的操作系统如UNⅨ等所采用的。为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运行”(running)和“阻塞”(blocking)三个工作状态。由于在任一时刻最多只有一个进程可以使用处理机,正占用着处理机的进程称为“运行”进程。当某进程已具备了使用处理机的条件,而当前又没有处理机供其使用,则使该进程处于“就绪”状态。当运行进程由于某种原因无法继续运行下去时,就停止其占用处理机,使之进入“阻塞”状态,待造成其退出运行的条件解除,再进入“就绪”状态。而对系统中所有同时运行的进程之间所存在的相互制约的同步(synchronization,指为了避免错误,在一个进程访问共享数据时,另一个进程不访问该数据)和互斥(mutually-exclusive,指两个进程不能同时在一个临界区中使用同一个可重复使用的资源,诸如读写缓冲区)两个关系,狄克斯特拉巧妙地利用火车运行控制系统中的“信号灯”(semaphore,或叫“信号量”)概念加以解决。所谓信号灯,实际上就是用来控制进程状态的一个代表某一资源的存储单元。例如,P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程,为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”,P操作和V操作是执行时不被打断的两个操作系统原语。执行P操作P(S)时信号量S的值减1,若结果大于等于0,则P(S)执行完毕,否则执行P操作的进程暂停以等待释放。执行V操作V(S)时,S的值加1,若结果大于0,则释放一个因执行P(S)而等待的进程。对P1和P2可定义两个信号量S1和S2,初值分别为1和0。进程P1在向缓冲B送入数据前执行P操作P(S1),在送入数据后执行V操作V(S2)。进程P2在从缓冲B读取数据前先执行P操作P(S2),在读出数据后执行V操作V(S1)。当P1往缓冲B送入一数据后信号量S1之值变为0,在该数据读出后S1之值才又变为1,因此在前一数未读出前后一数不会送入,从而保证了P1和P2之间的同步。
信号量是最早出现的用来解决进程同步与互斥问题的机制,
包括一个称为信号量的变量及对它进行的两个原语操作。
信号量的概念
1.信号量的类型定义
信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。
一般来说,信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S<0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
2.PV原语
PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用P V操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
对一个信号量变量可以进行两种原语操作:p操作和v操作,定义如下:procedure p(var s:semaphore);
{
s.value=s.value-1;
if (s.value<0) asleep(s.queue);
}
procedure v(var s:samephore);
{
s.value=s.value+1;
if (s.value<=0) wakeup(s.queue);
}
其中用到两个标准过程:
asleep(s.queue);执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态
wakeup(s.queue);将s.queue头进程唤醒插入就绪队列
s.value初值为1时,可以用来实现进程的互斥。
p操作和v操作是不可中断的程序段,称为原语。如果将信号量看作共享变量,则pv操作为其临界区,多个进程不能同时执行,一般用硬件方法保证。一个信号量只能置一次初值,以后只能对之进行p操作或v操作。
由此也可以看到,信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点。
V原语的主要操作是:
⑴sem加1;
⑵若相加结果大于零,则进程继续执行;
⑶若相加结果小于或等于零,则唤醒一阻塞在该信号量上的进程,然后再返回原进程继续执行或转进程调度。
利用信号量和PV操作实现进程互斥的一般模型是:
进程P1 进程P2 …… 进程Pn
……  ……  ……
P(S);  P(S);  P(S);
临界区;  临界区;  临界区;
V(S);  V(S);  V(S);
……  ……  …… ……
其中信号量S用于互斥,初值为1。
使用PV操作实现进程互斥时应该注意的是:
⑴每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
⑵P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
⑶互斥信号量的初值一般为1。
利用信号量和PV操作实现进程同步:
PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
使用PV操作实现进程同步时应该注意的是:
⑴分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
⑵信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
⑶同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。
典型理解偏差
三个问题:
一,以V原语的1、2步来做,Sem不就永远大于0,那进程不就一直循环执行成为死循环了?
二,Sem大于0那就表示有临界资源可供使用,为什么不唤醒进程?
三,Sem小于0应该是说没有临界资源可供使用,为什么还要唤醒进程?
析疑:
一,P操作对sem减1的。P、V原语必须成对使用!从而不会造成死循环。
二,Sem大于0的确表示有临界资源可供使用,而且这个时候没有进程被阻塞在这个资源上,也就是说没有进程因为得不到这类资源而阻塞,所以没有被阻塞的进程,自然不需要唤醒。
三,V原语操作的本质在于:一个进程使用完临界资源后,释放临界资源,使Sem加1,以通知其它的进程,这个时候如果Sem<0,表明有进程阻塞在该类资源上,因此要从阻塞队列里唤醒一个进程来“转手”该类资源。比如,有两个某类资源,四个进程A、B、C、D要用该类资源,最开始Sem=2,当A进入,Sem=1,当B进入Sem=0,表明该类资源刚好用完, 当C进入时Sem=-1,表明有一个进程被阻塞了,D进入,Sem=-2。当A用完该类资源时,进行V操作,Sem=-1,释放该类资源,而这时Sem<0,表明有进程阻塞在该类资源上,于是唤醒一个。
为了进一步加深理解,再引入二个问题:
四,如果是互斥信号量的话,应该设置信号量Sem=1,但是当有5个进程都访问的话,最后在该信号量的链表里会有4个在等待,也是说S=-4,那么第一个进程执行了V操作使S加1,释放了资源,下一个应该能够执行,但唤醒的这个进程在执行P操作时因S〈0,也还是执行不了,这是怎么回事呢?
五,Sem的绝对值表示等待的进程数,同时又表示临界资源,这到底是怎么回事?
析疑:
四,当一个进程阻塞了的时候,它已经执行过了P操作,并卡在临界区那个地方。当唤醒它时就立即进入它自己的临界区,并不需要执行P操作了,当执行完了临界区的程序后,就执行V操作。
五,当信号量Sem小于0时,其绝对值表示系统中因请求该类资源而被阻塞的进程数目.S大于0时表示可用的临界资源数。注意在不同情况下所表达的含义不一样。当等于0时,表示刚好用完。
========

操作系统之PV操作实例分析

http://blog.csdn.net/wulingmin21/article/details/7492737  


    刚开始学习操作系统的时候,就听说PV操作,简单说说PV操作。


●  P(S): S=S-1 
            如果S≥0,则该进程继续执行;
              S<0,进程暂停执行,放入信号量的等待队列
 
●  V(S): S=S+1
            如果S>0,则该进程继续执行;
                S≤0, 唤醒等待队列中的一个进程


    到底怎么分析,下面看看一个具体的问题:
    
首先设信号量S1,S2,其中
S1,表示是否允许司机启动汽车,其初值为0,
S2,表示是否允许售票员开车门,初值为O;
      


● 分析:
    司机进程:
            P:S1=S1-1 得:S1=0-1=-1<0 司机进程暂停执行,放入信号量的等待队列(售票员进程)
 
    售票员进程:
           关车门;
           V:S1=S1+1得:S1=-1+1=0≤ 0  唤醒等待队列中的一个进程


    (解释:唤醒司机进程,使司机进程成为就绪状态,司机可以启动车辆,正常行驶,……,直到到V(S2),  S2=S2+1 得:S2=0+1=1>0 ,司机进程在此时往下就没有操作了;
在唤醒司机进程的同时,售票员可以售票,执行售票进程,到P(S2)。
如果之前司机进程到V(S2),这里P(S2):S2=S2-1得:S2=1-1=0 ≥ 0,接着往下执行,到最后上下客;
如果之前司机进程未到V(S2),售票员的进程到P(S2),则如下进行)


           售票;(同时司机可能,启动车辆;正常行驶;……)
           P:S2=S2-1得:S2=0-1=-1< 0 售票员进程暂停执行,放入信号量的等待队列(运行司机进程)
 
    司机进程:   
         (接着上面未完成的继续往下执行)
          启动车辆;
          正常行驶;
          到站停车;
           S2=S2+1 得:S2=-1+1=0≤ 0 唤醒等待队列中的一个进程(运行售票员进程)
 
    售票员进程:
        开车门;
        上下客;


    以上过程(可以是如下):
          
     在售票员进程进程到V(S1),往下售票的同时司机可以启动车辆、……


● 使用PV操作实现进程同步时应该注意的是:
    (1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
    (2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
    (3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。
========

操作系统—PV操作

http://blog.csdn.net/wzh402/article/details/44889671


       大家都说操作系统中的PV操作部分看不懂,确实我在专业课中学习这门课时,PV操作被列为书中的重点和难点,就是因为它不好理解。当时自己听完课也是一头雾水,到期末考试结束,也没弄明白这是怎么一回事,更没有意识到PV操作的重要性。米老师的一堂课,让我开始对它产生兴趣,于是才有了这篇博客。首先就来说说什么是PV操作吧!


       什么是PV操作?


       在说什么是PV操作前,首先讲讲它的历史(咱也像写书的人一样,上来先介绍它的历史和发展)
       PV操作是有名的计算机科学家狄克斯特拉为了解决一类问题而创造的,例如:假如P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程,为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”。我相信,很多人都很纳闷为什么他会取名叫“PV”操作呢?其实这是狄克斯特拉用荷兰文定义的,因为在荷兰文中,“通过”叫passeren,“释放”叫vrijgeven,PV操作因此得名。这也是在计算机术语中不是用英语表达的极少数的例子之一。
       说了那么多,那到底什么叫PV操作呢?PV操作有P操作和V操作组成,它们是两个不可中断的过程,也叫做原语。它是为了能够实现对于并发进程中临界区的管理要求。


       为什么要有PV操作?


       其实这个问题上面也说到了,是为了防止两个进程并发时产生错误。这里不得不说的就是,并发进程之间分为两种,一种就是有交互的,一种是无任何关联的。
       很简单,没有关联的并发进程是相互独立的,谁也不影响谁。但是交互的并发进程可就不一样了,因为他们是共享资源的,一个进程运行时,经常会由于自身或外界的原因而被中端,且断点是不固定的。也就是说进程执行的相对速度不能由进程自己来控制,于是就会导致并发进程在共享资源的时出现与时间有关的错误。


       PV操作的使用


       名词解释


       临界区:我们把并发进程中与共享变量有关的程序段称为临界区。
       信号量S:信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。


       P操作和V操作


       P操作P(S):将信号量S减去1,若结果小于0,则把调用P(S)的进程置成等待信号量S的状态。即为请求资源。
       V操作V(S):将信号量S加上1,若结果不大于0,则释放一个等待信号量S的进程。即为释放资源。
       表示过程如下:
       Procedure P (Var S:Semaphore)
       begin
           S:=S - 1;
           if S<0 then W(S) 
       end; { P }
       
       Procedure V (Var S:Semaphore)
       begin
           S:=S + 1;
           if S< = 0 then R(S) 
       end; { V }
       注解:
       W(S):表示把调用P(S)的进程置成等待信号量S的状态。
       R(S):表示释放一个等待信号量S的进程。
       正如老师上课时所举的父亲给孩子吃苹果的例子一样,假如一个盘子只能放一个苹果,父亲往盘子里放了一个苹果。如果儿子吃了(V操作),父亲才可以接着放(P操作);如果儿子不吃,那父亲就不能放苹果,只能等着。


       进程互斥和进程同步


       进程互斥


       进程的互斥是指当有若干个进程都要使用某一共享资源时,任何时刻最多只允许一个进程去使用该资源,其他要使用它的进程必须等待,直到该资源的占用着释放了该资源。
       例如:两个并发进程都要使用共享的计数器Count。
       
[csharp] view plain copy print?
begin  
      count:integer;  
      S:semaphore;  
      count:= 0 //计数器count初始值为0  
      S:= 1 //信号量初始值为1  
   cobegin  
       //进程PIN  
       process PIN  
       R1:integer;  
       begin  
            P(S);  //执行P操作  
            R1:= count;  
            R1:= R1 + 1;  
            count:= R1;  
            V(S)  //执行V操作  
        end;  
       //进程POUT  
       process POUT  
       R2:integer;  
       begin  
            P(S);  //执行P操作  
            R2:= count;  
            R2:= R2 + 1;  
            count:= R2;  
            V(S)  //执行V操作  
        end;  
   coend  
end;  


       进程同步


       进程的同步是指在并发进程之间存在这一种制约关系,一个进程依赖另一个进程的消息,当一个进程没有得到另一个进程的消息时应等待,直到消息到达才被唤醒。
       例如:一个司机与售票员的例子,在公共汽车上,为保证乘客的安全,司机和售票员应协调工作:停车后才能开门,关车门后才能行车。用PV操作来实现他们之间的协调。
       S1:是否允许司机启动汽车的变量
       S2:是否允许售票员开门的变量
[csharp] view plain copy print?
driver()//司机进程  
{  
  while (1)//不停地循环  
  {   
   P(S1);//请求启动汽车  
   启动汽车;  
   正常行车;  
   到站停车;  
   V(S2); //释放开门变量,相当于通知售票员可以开门  
  }  
}  
[csharp] view plain copy print?
busman()//售票员进程  
{  
   while(1)  
   {  
    关车门;  
    V(S1);//释放开车变量,相当于通知司机可以开车  
    售票  
    P(S2);//请求开门  
    开车门;  
    上下乘客;  
   }  
}  


       总结:


       PV操作是操作系统中的重点和难点,不过如果细细分析,知道为什么要使用它以后。其实发现,PV操作也不过如此。并发进程间可以通过PV操作交换信息实现进程的互斥和同步,因此PV操作可以看做是进程间的一种低级的通信方式,只交换了少量的信息。但它解决了进程间对于资源共享而产生的与时间有关的错误。
========

信号量与PV操作

http://blog.chinaunix.net/uid-15014334-id-2853109.html
在计算机操作系统中,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)mod n;
     V(full);
}


消费者进程
while(TRUE){
 P(full);
   从buffer(out)中取出产品;
   out=(out+1)mod n;
   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)mod n;
     V(mutex1);
     V(full);
}
消费者进程
while(TRUE){
 P(full)
   P(mutex2);
   从buffer(out)中取出产品;
   out=(out+1)mod n;
   V(mutex2);
   V(empty);
   消费该产品;
   }
  需要注意的是无论在生产者进程中还是在消费者进程中,两个P操作的次序不能颠倒。应先执行同步信号量的P操作,然后再执行互斥信号量的P操作,否则可能造成进程死锁。
【例2】桌上有一空盘,允许存放一只水果。爸爸可向盘中放苹果,也可向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放一只水果供吃者取用,请用P、V原语实现爸爸、儿子、女儿三个并发进程的同步。
分析 在本题中,爸爸、儿子、女儿共用一个盘子,盘中一次只能放一个水果。当盘子为空时,爸爸可将一个水果放入果盘中。若放入果盘中的是桔子,则允许儿子吃,女儿必须等待;若放入果盘中的是苹果,则允许女儿吃,儿子必须等待。本题实际上是生产者-消费者问题的一种变形。这里,生产者放入缓冲区的产品有两类,消费者也有两类,每类消费者只消费其中固定的一类产品。
    解:在本题中,应设置三个信号量S、So、Sa,信号量S表示盘子是否为空,其初值为l;信号量So表示盘中是否有桔子,其初值为0;信号量Sa表示盘中是否有苹果,其初值为0。同步描述如下:
int S=1;
int Sa=0;
int So=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];
      read F;             read F;                read F;              read F;
     [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个时,暂停对数量大的食品进货,补充数量少的食品。
(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;     // 互斥信号量,初值均为1
semaphore  S_boys; // 男生等待队列,初值为0
semaphore  S_girls;   // 女生等待队列,初值为0
普通变量的定义:
int  boys_waiting = 0;     // 正在等待的男生数;
int  girls_waiting = 0; // 正在等待的女生数;
int  using = 0;      // 当前是否有人在使用浴室;
void  boy_wants_to_use_bathroom ( )
{
        P(S_mutex);
        if((using == 0) && (girls_waiting == 0))
         {
                using  =  1;
                V(S_mutex);
         }
        else
         {
                boys_waiting ++;
                V(S_mutex);
                P(S_boys);
         }
}
void  boy_leaves_bathroom ( )
{
        P(S_mutex);
        if(girls_waiting  >  0)  // 优先唤醒女生
         {
                girls_waiting --;
                V(S_girls);
         }
        else  if(boys_waiting  >  0)
         {
                boys_waiting --;
                V(S_ boys);
         }
        else    using  =  0;         // 无人在等待
        V(S_mutex);
}
void  girl_wants_to_use_bathroom ( )
{
        P(S_mutex);
        if(using == 0)
         {
                using  =  1;
                V(S_mutex);
         }
        else
         {
                girls_waiting ++;
                V(S_mutex);
                P(S_girls);
         }
}
void  girl_leaves_bathroom ( )
{
        P(S_mutex);
        if(girls_waiting  >  0)  // 优先唤醒女生
         {
                girls_waiting --;
                V(S_girls);
         }
        else  if(boys_waiting  >  0)
         {
                boys_waiting --;
                V(S_ boys);
         }
        else    using  =  0;         // 无人在等待
        V(S_mutex);
}


========

实验四 简单的PV操作

http://www.cnblogs.com/amzinghui/p/5607219.html


一、        实验目的


1.掌握临界区的概念及临界区的设计原则;


2.掌握信号量的概念、PV操作的含义以及应用PV操作实现进程的同步与互斥;


3.分析进程争用资源的现象,学习解决进程互斥的方法。


二、        实验内容和要求


分析进程的同步与互斥现象,编程实现经典的进程同步问题——生产者消费者问题的模拟


生产者--消费者问题表述:


有一环形缓冲池,包含n个缓冲区(0~n-1)。


有两类进程:一组生产者进程和一组消费者进程,生产者进程向空的缓冲区中放产品,消费者进程从满的缓冲区中取走产品。


所有进程必须对缓冲区进行互斥的访问。


生产者不能向满缓冲区写数据,消费者不能从空缓冲区取数据,即生产者与消费者必须同步。


计算机系统中对资源的分配与释放过程:计算机系统中的每个进程都可以消费或生产某类资源。当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。而当某个进程释放资源时,则它就相当一个生产者。


定义生产者消费者问题中的各数据结构,并初始化。


信号量,初值。


编写PV操作。


编写生产者与消费者程序,利用信号量及其PV操作,实现生产者与消费者之间的同步与互斥。


模拟显示生产者与消费者同步与互斥的效果。


三、 实验方法、步骤及结果测试


#include


#include


#include


#include


#define N 50


typedef struct process


{


   int i;


}P;


P a[N];


int workingtime=0;


void main(){


int a=0,b;


int flag=1;


int p=0,v=0;


int n,i;


printf("你想要货架上有多少空间?\n");


scanf("%d",&n);


while(flag==1)


{


srand(time(NULL));


b=rand()%2+1;


if(b==1)


{


   if(a<5&&p==0&&v==0)


   {


      p++;


      v++;


          a++;


   printf("放置商品\n");


   p--;


      v--;


   }


else{


printf("无法放置更多的商品\n");


}  


  


}


else


{


if(a>0&&p==0&&v==0)


{


      p++;


      v++;


   a--;


   printf("商品已被消费\n");


      p--;


      v--;


}


else{


printf("现在货架上并没有商品\n");


}  


 


}


printf("继续请输1,退出请输2\n");


scanf("%d",&flag);


 


}


}


四、 实验总结


此次实验除了用c语言实现PV操作的问题上有点困难,只能在显示效果上模拟,并且成功完成了试验要求。
========

你可能感兴趣的:(操作系统研发和研究,操作系统,pv操作)