PV 操作解析

来源:互联网 发布:deepin linux硬件需求 编辑:程序博客网 时间:2024/06/04 23:22

PV操作详解

 

    1965年,荷兰学者Dijkstra提出的信号量机制是一种进程同步工具。其基本原则是在多个相互合作的进程之间使用简单的信号来协调控制。一个进程检测到某个信号后,就被强迫停止在一个特定的地方,直到它收到一个专门的信号为止才能继续执行。这个信号就称为“信号量”。其工作方式有点类似于十字路口的交通控制信号灯。信号量的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。注意:号量的值仅能由PV操作来改变。

    本思路是用一种新的变量类型(semaphore)来记录当前可用资源的数量。semaphore有两种实现方式:  

    1) semaphore的取值必须大于或等于0。0表示当前已没有空闲资源,而正数表示当前空闲资源的数量;

    2) semaphore的取值可正可负,负数的绝对值表示正在等待进入临界区的进程个数。  

    信号量是由操作系统来维护的,用户进程只能通过初始化和两个标准原语(P、V原语)来访问。初始化可指定一个非负整数,即空闲资源总数。  

   P原语:P是荷兰语Proberen(测试)的首字母。为阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;

P原语操作的动作是:
    (1)sem减1;
    (2)若sem减1后仍大于或等于零,则进程继续执行;
    (3)若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。

   V原语:V是荷兰语Verhogen(增加)的首字母。为唤醒原语,负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。

    V原语操作的动作是:
    (1)sem加1;
    (2)若相加结果大于零,则进程继续执行;
    (3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。

 

    PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

1.  利用信号量和PV操作实现进程互斥的一般模型是:其中信号量S用于互斥,初值为1。

使用PV操作实现进程互斥时应该注意的是:

(1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。

(2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。

(3)互斥信号量的初值一般为1。

2.  利用信号量和PV操作实现进程同步

PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。

    使用PV操作实现进程同步时应该注意的是:

    (1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。

    (2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。

    (3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。

 

例子:生产者-消费者问题分析:

    在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。

 

(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操作,否则可能造成进程死锁。

原创粉丝点击