首先解释几个概念:
1、同步和互斥:对于多道程序设计的系统,进程可以并发执行,就会存在资源共享和相互合作的问题,从而引发互斥和同步。
同步:合作进程之间的直接制约问题,例如一个buffer,进程A往里写data,进程B从里读data,这就要求B必须等待A完成写入操作后才可以读取。由此看出,同步就是进程间为了完成某 一个任务时,直接发生的互相作用的关系。
互斥:多个进程可以共享资源,但由于有一些资源,在同一时刻,只能由一个进程占有,比如打印机,从而引发互斥问题。
2、临界资源和临界区:
临界资源是指一次只能供一个进程使用的资源,比如打印机、共享变量等。
临界区是指进程中对临界资源进行操作的那段程序。当多个进程互斥使用临界资源,临界区的执行便同时互斥。对临界区的管理原则是:有空就进,无空等待,有限等待,让权等待(即当进程无法进入自己的临界区,便立即释放处理机,以免进程进入忙等状态)
3、信号量机制
信号量机制设计目的就是为了控制进程间的互斥和同步。主要有整型信号量、记录型信号量和信号量集机制。
这里主要说整形信号量,信号量就是一个整型变量(这里都用S表示),分为以下两类:
1)公用信号量:实现进程间的互斥,初始值为1或者资源的数目。
(这个好理解,就是为标识有几个临界资源,比说一个打印机,那么初始值S=1,进程A先申请了,S=S-1;此时B来申请,S=0没有资源了,那就等待,等A完成打印操作后释放资源重新设置信号S=S+1)
2)私有信号量:实现进程间的同步,初始值为0或者某个正整数。
(这就是个信号,比如S=0表示可以继续操作,其他值表示不能继续操作。进程A写数据IF S=0 THEN S=S-1; WRITE;END这时,进程B如果想读数据发现S<0,则表示不能继续下面操作,要等待,等A完成写操作S=S+1后,B才可以读操作)
----------------------------------------------------------------------------------------------------------------------------------------------------
现在正式介绍PV操作
1、首先要明白:P操作和V操作都是原语,即他们都是不可分割的。比如P操作,不管中间你要执行什么程序,整个P操作要么不执行,要么就要全部执行。
2、信号量的值的意义:当S >=0 时,表示某资源的可用数。S<0时,|S|表示阻塞队列中等待该资源的进程数。这个理解PV操作时候要常想想。
2、P操作定义:P操作用来申请一个资源;首先S=S-1,若S>=0,则继续后面的操作;如果S<0,则该进程进入等待队列(我是这么理解这句话的:上来先S=S-1,因为进程必行,要抢资源滴,你懂得,有资源就先抢个资源,即使没有,也抢个前排的座。S>0好理解,说明还有的是资源呢,我就不管了继续后面操作。S=0呢,说明刚刚最后一个资源被我抢了,不管别人,我先执行后面操作。S<0,那么你悲催了,说明有人排队呢,你当然也要排队,你要等待别人用完才行)
Procedure P(var s:Semaphore){
s=s-1;
if(s<0) W(s); //执行P操作的进程进入等待队列
}
3、V操作定义:V操作用来释放一个资源;首先S=S+1,若S>0,则继续后面的操作;若S<=0,则从阻塞队列中唤醒一个进程,并将其插入就绪队列,然后执行V操作的进程继续。(这句话可以这样理解:V操作就是为了释放资源。所以上来就要S=S+1,别耽误别人使用资源。S>0说明资源很充足啊,不用管,咱继续;S<=0,说明你释放资源之前,是有人排队等着来,你释放资源后,就要告诉后面排队的“喂,醒醒,哥刚用完了该资源让出来了,下面该你用了,等CPU临幸吧”)
Procedure V(var s:Semaphore){
s=s+1;
if(s<=0) R(s); //从阻塞队列中唤醒一个进程
}
---------------------------------------------------------------------------------
下面用PV操作实现控制互斥和同步
1、互斥
令信号量s初始值为1,进入临界区时,执行P操作,退出临界区时执行V操作;
比如有个共享变量count,进程A临界区count=1; print count;进程B临界区count=0; print count;
A程序:
A{ B{
P(s); P(s);
count=1; count=0;
print count;print count;
V(s); V(s);
} }
2、同步:
同步就是进程A和B之间的制约问题,所以信号量S表示一个信号,通知进程A、B的一个消息。比如初始值s=0,表示希望的消息没发生,不准许继续操作,当s!=0时,表示希望的消息发生了,准许下面的操作了。
典型的是单缓冲区的生产者-消费者问题。
1)一个缓冲区,可以放入一个产品,A生产产品放入缓冲区,B从缓冲区取产品。设置两个信号量:s1表示缓冲区是否为空即能否往里放产品,s2表示缓冲区中是否有产品即能否从里取产品。
A--->生产一个产品;
P(s1); //判断能不能放
往缓冲区放入一个产品;
V(s2); //通知可以取
B--->
P(s2);
从缓冲区取出一个产品;
V(s2);
消费;
2)同样一个缓冲区,但可以放入多个产品,A、B不断的放入取出。这时候,就要再格外添加一个互斥信号量S,因为缓冲区是互斥资源。
A--->生产一个产品;
P(s1);
P(S);
将产品放入缓冲区;
V(S);
V(s2);
B--->
P(s2);
P(S);
从缓冲区取出一个产品;
V(S);
V(s2);
消费;