PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
P(S):①将信号量S的值减1,即S=S-1;
②如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;
②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。
交互的并发进程因为他们共享资源,一个进程运行时,经常会由于自身或外界的原因而被中端,且断点是不固定的。也就是说进程执行的相对速度不能由进程自己来控制,于是就会导致并发进程在共享资源的时出现与时间有关的错误。
临界区 : 我们把并发进程中与共享变量有关的程序段称为临界区。
信号量S : 信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
进程的互斥 是指当有若干个进程都要使用某一共享资源时,任何时刻最多只允许一个进程去使用该资源,其他要使用它的进程必须等待,直到该资源的占用着释放了该资源。进程的同步是指在并发进程之间存在这一种制约关系,一个进程依赖另一个进程的消息,当一个进程没有得到另一个进程的消息时应等待,直到消息到达才被唤醒。
【例1】生产者-消费者问题
在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。
①一个生产者,一个消费者,公用一个缓冲区。
empty——表示缓冲区是否为空,初值为1。
full——表示缓冲区中是否为满,初值为0。
生产者进程:
p(empty);
向buffer放产品;
v(full);
消费者进程:
p(full);
从buffer取产品;
v(empty);
②n个生产者,n个消费者,公用n个缓冲区。
在这个问题中,不仅生产者与消费者之间要同步,而且各个生产者之间、各个消费者之间还必须互斥地访问缓冲区.
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。
生产者进程:
生产一件产品;
P(empty);
P(mutex1);
产品送往buffer(in);
in=(in+1)mod n;
V(mutex1);
V(full);
消费者进程;
P(mutex2);
从buffer(out)中取出产品;
out=(out+1)mod n;
V(mutex2);
V(empty);
消费该产品;
从上例中可以看出实现进程间互斥时:
信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。
P(S); //通过
使用该资源;
V(S); //释放
实现进程间同步时:
A进程:
P(S);
传数据到buffer;
V(S1);
B进程:
P (S1);
从buffer取数据;
V(S);
A/B进程互为前提,互相制约。
例子:
利用PV操作变量实现前趋图:
用PV操作控制进程并发执行的过程,则需要相应于进程执行过程设置5个信号量S1、S2、S3、S4和S5,且信号量初值都等于零。
则实现过程:
P1;
V(S1);
V(S2);
P(S1);
P2;
V(S3);
P(S2);
P3;
V(S4);
P(S3);
P(S4);
P4;
V(S5);
P(S5);
P5;