操作系统 第二部分 进程管理(六)

本文探讨了生产者-消费者问题、哲学家进餐问题及读者-写者问题等经典的并发编程同步问题。通过记录型信号量、AND信号量及管程等机制解决了资源互斥访问的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

6) 综合应用:生产者消费者问题、读者和写者问题、哲学家进餐问题等。

2.4.1  生产者—消费者问题

1 .利用记录型信号量解决生产者— 消费者问题
  假定在生产者和消费者之间的公用缓冲池中,具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用。利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。对生产者—消费者问题可描述如下:

Var mutex,empty,full: semaphore:=1,n,0;
  buffer:array[0,…,n-1] of item;
  in,out: integer:=00;
  begin
   parbegin
   proceducer: begin
         repeat
            
         producer an item nextp;
            
         wait(empty);
         wait(mutex);
         buffer(in):=nextp;
         in:=(in+1) mod n;
         signal(mutex);
         signal(full);
         until false;
       end
   consumer: begin
        repeat
          wait(full);
          wait(mutex);
          nextc:=buffer(out);
          out:=(out+1) mod n;
            signal(mutex);
            signal(empty);
            consumer the item in nextc;
           until false;
          end
    parend
  end

在生产者—消费者问题中应注意:首先,在每个程序中用于实现互斥的wait(mutex)和signal(mutex)必须成对地出现;其次,对资源信号量empty和full的wait和signal操作,同样需要成对地出现,但它们分别处于不同的程序中。例如,wait(empty)在计算进程中,而signal(empty)则在打印进程中,计算进程若因执行wait(empty)而阻塞,则以后将由打印进程将它唤醒;最后,在每个程序中的多个wait操作顺序不能颠倒,应先执行对资源信号量的wait操作,然后再执行对互斥信号量的wait操作,否则可能引起进程死锁。

2 .利用AND 信号量解决生产者— 消费者问题
 对于生产者—消费者问题,也可利用AND信号量来解决,即用Swait(empty,mutex)来代替wait(empty)和wait(mutex);用Ssignal(mutex,full)来代替signal(mutex)和signal(full);用Swait(full,mutex)来代替wait(full)和wait(mutex),以及用Ssignal(mutex,empty)代替Signal(mutex)和Signal(empty)。利用AND信号量来解决生产者—消费者问题的算法描述如下:

Var mutex,empty,full: semaphore:=1,n,0;
   buffer:array[0,…,n-1] of item;
   in out: integer:=00;
  begin
   parbegin
     producer: begin
            repeat
            
            produce an item in nextp;
            
            Swait(empty,mutex);
            buffer(in):=nextp;
            in:=(in+1)mod n;
            Ssignal(mutex,full);
           until false;
         end
         consumer:begin
          repeat
           Swait(full,mutex);
           Nextc:=buffer(out);
           Out:=(out+1) mod n;
           Ssignal(mutex,empty);
           consumer the item in nextc;
         until false;
       end
     parend
  end

3 .利用管程解决生产者— 消费者问题
 在利用管程方法来解决生产者—消费者问题时,首先便是
为它们建立一个管程,并命名为ProclucerConsumer,或简称
为PC。其中包括两个过程:
  (1) put(item)过程。生产者利用该过程将自己生产的产品
投放到缓冲池中,并用整型变量count来表示在缓冲池中已有
的产品数目,当count≥n时,表示缓冲池已满,生产者须等待。
  (2) get(item)过程。消费者利用该过程从缓冲池中取出一
个产品,当count≤0时,表示缓冲池中已无可取用的产品,消
费者应等待。

PC管程可描述如下:
  type producer-consumer=monitor
    Var in,out,count: integer;
     buffer: array[0,, n-1] of item;
     notfull,notempty:condition;
     procedure entry put(item)
       begin
        if count>=n then notfull.wait;
         buffer(in):=nextp;
         in:=(in+1) mod n;
         count:=count+1;
         if notempty.queue then notempty.signal;
        end
        procedure entry get(item)
       begin
        if count<=0 then notempty.wait;
        nextc:=buffer(out);
        out:=(out+1) mod n;
        count:=count-1;
        if notfull.quene then notfull.signal;
       end
    begin in:=out:=0;
count:=0
end
在利用管程解决生产者—消费者问题时,其中的生产者和消
费者可描述为:
  producer: begin
        repeat
         produce an item in nextp;
         PC.put(item);
        until false;
       end
  consumer: begin
        repeat
         PC.get(item);
         consume the item in nextc;
        until false;
       end

2.4.2 哲学家进餐问题
  1 .利用记录型信号量解决哲学家进餐问题
  经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用。为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组。其描述如下:
  Var chopstick: array[0,…,4] of semaphore;

所有信号量均被初始化为1,第i位哲学家的活动可描述为:
  repeat
    wait(chopstick[i]);
    wait(chopstick[(i+1)mod 5]);
     
    eat;
     
    signal(chopstick[i]);
    signal(chopstick[(i+1)mod 5]);
     
    think;
  until false;

在以上描述中,当哲学家饥饿时,总是先去拿他左边的筷子,即执行wait(chopstick[i]); 成功后,再去拿他右边的筷子,即执行wait(chopstick[(i+1)mod 5]);又成功后便可进餐。进餐完毕,又先放下他左边的筷子,然后再放右边的筷子。虽然,上述解法可保证不会有两个相邻的哲学家同时进餐,但有可能引起死锁。假如五位哲学家同时饥饿而各自拿起左边的筷子时,就会使五个信号量chopstick均为0; 当他们再试图去拿右边的筷子时,都将因无筷子可拿而无限期地等待。对于这样的死锁问题,可采取以下几种解决方法:
(1) 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
(2) 仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐。
(3) 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子,而偶数号哲学家则相反。按此规定,将是1、2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐。
 2 .利用AND 信号量机制解决哲学家进餐问题
  在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐,这在本质上就是前面所介绍的AND同步问题,故用AND信号量机制可获得最简洁的解法。描述如下:

Var chopsiick array of semaphore:=(1,1,1,1,1);
  processi
   repeat
     think;
     Sswait(chopstick[(i+1)mod 5],chopstick[i]);
     eat;
     Ssignat(chopstick[(i+1)mod 5],chopstick[i]);
   until false;
2.4.3  读者—写者问题

1 .利用记录型信号量解决读者— 写者问题
  为实现Reader与Writer进程间在读或写时的互斥而设置了一个互斥信号量Wmutex。另外,再设置一个整型变量Readcount表示正在读的进程数目。由于只要有一个Reader进程在读,便不允许Writer进程去写。因此,仅当Readcount=0,表示尚无Reader进程在读时,Reader进程才需要执行Wait(Wmutex)操作。若Wait(Wmutex)操作成功,Reader进程便可去读,相应地,做Readcount+1操作。同理,仅当Reader进程在执行了Readcount减1操作后其值为0时,才须执行signal(Wmutex)操作,以便让Writer进程写。又因为Readcount是一个可被多个Reader进程访问的临界资源,因此,也应该为它设置一个互斥信号量rmutex。

读者—写者问题可描述如下:
  Var rmutex,wmutex: semaphore:=1,1;
    Readcount: integer:=0;
    begin
    parbegin
     Reader: begin
        repeat
         wait(rmutex);
         if readcount=0 then wait(wmutex);
          Readcount:=Readcount+1;
         signal(rmutex);
         perform read operation;
          
         wait(rmutex);
         readcount:=readcount-1;
         if readcount=0 then signal(wmutex);
         signal(rmutex);
        until false;
       end
    writer: begin
        repeat
         wait(wmutex);
         perform write operation;
         signal(wmutex);
        until false;
       end
    parend
  end

2 .利用信号量集机制解决读者— 写者问题
  这里的读者—写者问题与前面的略有不同,它增加了一个限制,即最多只允许RN个读者同时读。为此,又引入了一个信号量L,并赋予其初值为RN,通过执行wait(L,1,1)操作,来控制读者的数目。每当有一个读者进入时,就要先执行wait(L,1,1)操作,使L的值减1。当有RN个读者进入读后,L便减为0,第RN+1个读者要进入读时,必然会因wait(L,1,1)操作失败而阻塞。对利用信号量集来解决读者—写者问题的描述如下:

Var RN integer;
    L,mx: semaphore:=RN,1;
   begin
    parbegin
     reader: begin
        repeat
         Swait(L,1,1);
         Swait(mx,1,0);
          
         perform read operation;
          
         Ssignal(L,1);
        until false;
       end
       writer: begin
         repeat
          Swait(mx,1,1;L,RN,0);
          perform write operation;
          Ssignal(mx,1);
        until false;
       end
    parend
  end

其中,Swait(mx,1,0)语句起着开关的作用。只要无writer进程进入写,mx=1,reader进程就都可以进入读。但只要一旦有writer进程进入写时,其mx=0,则任何reader进程就都无法进入读。Swait(mx,1,1;L,RN,0)语句表示仅当既无writer进程在写(mx=1),又无reader进程在读(L=RN)时,writer进程才能进入临界区写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值