基本概念
临界区:我们把并发进程中与共享变量有关的程序段称为临界区。
进程的同步:指在并发进程之间存在一种制约关系,一个进程的执行依赖另一个进程的消息,当一个进程没有得到另一个进程的消息时应等待,直到消息到达才被唤醒。
进程的互斥:指当有若干个进程都要使用某一共享资源时,任何时候最多只允许一个进程去使用该资源,其他要使用它的进程必须等待,直到该资源的占用者释放了该资源。
P操作P(s):将信号量减去1,若结果小于0,则把调用P(s)的进程置成等待信号量S的状态。
V操作V(s):将信号量S加1,若结果不大于0,则释放一个等待信号量S的进程。
原语:两种操作是不可分割的整体,即:两种操作要么都执行,要么都不执行。和我们数据库中事务的原子性一个道理。
P操作原语:
Procedure P(Var s:Semaphore)
begin:
s:=s-1;
if s<0 then
wait
end;
V操作原语
Procedure V(var:s Semaphore);
begin
s:=s+1;
if s <=0 then
Run(s);
end;
【经典案例】
案例图:
案例描述:
此案例是描述的父亲和儿子关于吃苹果的问题,现在在父子之间只有一个盘子的空间,并且此盘子只能存放一个苹果,只有当盘子中没有苹果的时候父亲才能往盘子中放入苹果,否则父亲处于等待状态;只有盘子中有一个苹果的时候,儿子才能从盘子中拿苹果吃,否则也只能处于等待状态;本来这个一个互锁的事情,现在用P/V操作来解决这个问题。
案例转化:
设:S1=1,S2=0(即盘子中没有苹果,父亲可以放,儿子处于等待状态)
父:
P操作(查看自己是否有能力放苹果)
S1=S1-1; S1=0;(减1是个假动作,只有当S1-1>=0时,才自动减1,并启动V操作)
V操作(通知儿子盘子里有苹果,可以来拿)
S2=S2+1; S2=1;
子:
P操作:(查看自己能不能拿苹果)
S2=S2-1; S2=0;
V操作:(通知父亲又可以来放苹果)
S1=S1+1; S1=1;
案例总结:
P/V操作的本质其实就是解耦,对于吃苹果的问题本来是一个整体的过程,父亲和儿子都在关注盘子的状态,是一个互锁的状态,但是现在引入P/V操作,使信号量S分成两个信号量S1、S2,使父子都只关注自己的这一部分的信号量的变化,不必考虑对方,这样减少了复杂的联系,解耦合。当然当父亲P操作之后还是要通知儿子的。这就是P/V操作的妙处。