简单理解操作系统中的PV操作

可以这样理解:
临界区门前有棵树
用来挂红灯
进程想进CPU的门
先得上树取下盏灯(调用一次P)
取下一个去敲门(S=S-1)
如果树上没有灯取(S<=0)
树说暂时欠你一盏灯(S为负时)
进程没辙只好在门外边排队等(WAIT(S))
得灯的进程继续运行运行完了要出门(调用一次V)
马上还回一盏灯(S=S+1)
若有进程在催债(S<=0)
放个进程进去完成(Release(S))

 

概念难点解析
V原语的主要操作是:

(1)sem加1;

(2)若相加结果大于零,则进程继续执行;

(3)若相加结果小于或等于零,则唤醒一阻塞在该信号量上的进程,然后再返回原进程继续执行或转进程调度。



P操作顺序执行下述两个动作:
①信号量的值减1,即S=S-1; 
②如果S≥0,则该进程继续执行;
如果S<0,则把该进程的状态置为阻塞态,把相应的PCB连入该信号量队列的末尾,并放弃处理机,进行等待(直至其它进程在S上执行V操作,把它释放出来为止).
V操作顺序执行下述两个动作:
①S值加1,即S=S+1;
②如果S>0,则该进程继续运行;
如果S≤0,则释放信号量队列上的第一个PCB(即信号量指量指针项所指向的PCB)所对应的进程(把阻塞态改为就绪态),执行V操作的进程继续运行.



典型理解偏差:

一,以V原语的1、2步来做,Sem不就永远大于0,那进程不就一直循环执行成为死循环了?

二,Sem大于0那就表示有临界资源可供使用,为什么不唤醒进程?

三,Sem小于0应该是说没有临界资源可供使用,为什么还要唤醒进程?
析疑:

一,P操作对sem减1的。P、V原语必须成对使用!从而不会造成死循环。

二,Sem大于0的确表示有临界资源可供使用,而且这个时候没有进程被阻塞在这个资源上,也就是说没有进程因为得不到这类资源而阻塞,所以没有被阻塞的进程,自然不需要唤醒。

三,V原语操作的本质在于:一个进程使用完临界资源后,释放临界资源,使Sem加1,以通知其它的进程,这个时候如果Sem<0,表明有进程阻塞在该类资源上,因此要从阻塞队列里唤醒一个进程来“转手”该类资源。

比如,有2个某类资源,三个进程A、B、C、D要用该类资源,最开始Sem=2,当A进入,Sem=1,当B进入Sem=0,表明该类资源刚好用完,

当C进入时Sem=-1,表明有一个进程被阻塞了,D进入,Sem=-2。当A用完该类资源时,进行V操作,Sem=-1,释放该类资源,而这时Sem<0,表明有进程阻塞在该类资源上,于是唤醒一个。
为了进一步加深理解,再引入二个问题:

四,如果是互斥信号量的话,应该设置信号量Sen=1,但是当有5个进程都访问的话,最后在该信号量的链表里会有4个在等待,也是说S=-4,那么第一个进程执行了V操作使S加1,释放了资源,下一个应该能够执行,但唤醒的这个进程在执行P操作时因S〈0 ,也还是执行不了,这是怎么回事呢?

五,Sem的绝对值表示等待的进程数,同时又表示临界资源,这到底是怎么回事?

析疑:

四,当一个进程阻塞了的时候,它已经执行过了P操作,并卡在临界区那个地方。当唤醒它时就立即进入它自己的临界区,并不需要执行P操作了,当执行完了临界区的程序后,就执行V操作。

五,当信号量Sem小于0时,其绝对值表示系统中因请求该类资源而被阻塞的进程数目.S大于0时表示可用的临界资源数。注意在不同情况下所表达的含义不一样。当等于0时,表示刚好用完。

 

★     信号量、PV操作是解决进程间的同步与互斥问题的。

★     做题时尤其要注意隐藏的同步、互斥问题。这些问题通常可以归入生产者-消费者问题和阅读者-写入者问题。

★     PV操作一定是成对出现的,但是这不意味着它会在一个进程内成对出现。

★     在互斥关系中,PV操作一定是在一个进程内成对出现。而且,信号一定大于0,具体多少视情况而定。而对于同步关系,则一对PV操作在两个进程或者更多的进程中出现。

★     对于同步关系,信号量可能为0,也可能不为0;用于同步的信号个数可能1个,也可能是多个。

★     对信号量为1的,应该先执行V操作。

★     在生产者-消费者问题中,要设置三个信号量:empty-空闲的缓存区数量,初值为n;full-已填充的缓存区数量,初值为0;mutex-保证只有一个进程在写入缓存区,初值为1。

★     在阅读者-写入者问题中,设置两个信号量:信号量access-控制写入互斥,初值为1;信号量rc-控制对共享变量ReadCount(读者统计值)的互斥访问。



P:申请一个资源
V:释放一个资源
struct semaphore
{
 int value;//信号量的值,表示可用资源的数目
 List_of_precess L;//在此信号量上等待的进程队列的对手指针
}S;
 if(S.value>0):可供使用的资源的数目
 if(S.value==0):无资源、无进程等待
 if(S.value<0):相反数为等待使用资源的进程的数目
 
 
在信号量上,可建立如下的P、V操作

void P(S)
{
 lock interrupts;//中断
 S.value--;
 if(S.value<0)
 {
  add this process to S.L;
  block;
 }
}
void V(S)
{
 S.value++;
 if(S.value<=0)
 {
  remove a process Pi from S.L;
  unlock(Pi);
 }
}

为了使多个进程互斥地进入各自的同类临界区,可以设置一个互斥信号量,例如mutex,置初始值为1,
并在每一个临界区的前后插入此信号量上的P、V操作,是每个进程有如下结构
void P(int i)
{
 while(true)
 {
  P(mutex);
  critical section;
  V(mutex);
  non-critical section;
 }
}

考虑两个进程P1、P2,P1有程序S1,P2有程序S2。要求设计一个同步方案,使得S1在S2完成以后才执行,为此,
设置一个信号量synch,初始值为0,并使P1、P2有如下形式
void P1()
{
 ...
 P(synch);
 S1;
 ...
}

void P2()
{
 ...
 S2;
 V(synch);
 ...
}


生产者、消费者问题
void main()
{
 int full=0,//满缓冲区的数量
  empty=0,//空缓冲区的数量
  mutex=1,//对有界缓冲区进行操作的互斥信号量
  in=0,
  out=0;
 buffer[n];
 cobegin
  producer();
  consumer();
 coend
}
void prodeucer()
{
 while(true)
 {
  ...
  produce an item in nextp;//生产一件产品
  ...
  P(empty);
  P(metux);
  buffer[in]=nextp;//向缓冲区放一件产品
  in=(++in)%n;
  V(mutex);
  V(full);
 }
}
void consumer()
{
 while(true)
 {
  P(full);
  P(mutex);
  nextc=buffer[out];
  out=(++out)%n;
  V(mutex);
  V(empty);
  consume the item in nextc;
 }
}
在生产者、消费者问题中应该注意:
1、在每个程序中用于实现互斥的P、V操作必须成对出现
2、对资源信号量的操作,同样需要成对的出现,但他们可以处于不同的程序中
3、在每个程序中多个P操作顺序不能颠倒,否则在一定条件下会出现死锁现象

猜你喜欢

转载自blog.csdn.net/qq_32146369/article/details/78634365