2016-12-14 56 views
0

classical producer-consumer problem中,当共享缓冲区已满且使用者等待共享缓冲区为空时,我们有生产者等待。我们有两个posix线程,一个生产者和其他工作者,使用sem_wait和sem_post为空信号量和完整信号量(两个计数信号量)相互同步。因此,信号量实现生产者 - 消费者代码看起来如下:具有异常处理功能以防止死锁的C++ Producer-Consumer

procedure producer() { 
    while (true) { 
     item = produceItem(); 
     down(emptyCount); 
      down(buffer_mutex); 
       putItemIntoBuffer(item); 
      up(buffer_mutex); 
     up(fillCount); 
    } 
} 

procedure consumer() { 
    while (true) { 
     down(fillCount); 
      down(buffer_mutex); 
       item = removeItemFromBuffer(); 
      up(buffer_mutex); 
     up(emptyCount); 
     consumeItem(item); 
    } 
} 

。假定生产商()和消费者()在独立并发线程运行,当produceItemconsumeItem面临的一个运行时异常会发生什么导致线程优雅地处理异常,这样两个线程才能优雅地出来? 哪里可以试试catch来处理这种情况?

+0

什么是你预料之外的本质是什么?如果生产者未能写入共享缓冲区,那么生产者应该处理该异常,并且消费者不应该意识到该异常。如果消费者未能从共享缓冲区读取消息,则消费者应该处理该异常,并且生产者不应该意识到该异常。 –

+0

@JimRogers consumeItem(item)和/或produceItem()可能面临异常 –

+0

这是真的,但两个线程之间唯一的接口是缓冲区。如果生产者遇到异常,则消费者将等待它从异常中恢复。同样,如果消费者遇到异常,生产者将等待消费者从异常中恢复。如果担心生产者或消费者无法从异常中恢复,那么应该等待每个线程等待访问缓冲区。 –

回答

0

我使用Ada进行大多数多线程处理。下面的Ada示例显示了如何将超时应用于等待条件变量允许消费者处理非响应式生产者以及生产者处理非响应式消费者。

------------------------------------------------------------------ 
-- Producer-Consumer Package -- 
------------------------------------------------------------------ 
with Ada.Text_IO; use Ada.Text_IO; 

procedure Protected_Producer_Consumer is 
    protected Buffer is 
     entry Put(Item : in Integer); 
     entry Get(Item : out Integer); 
    private 
     Value : Integer := Integer'First; 
     Is_New : Boolean := False; 
    end Buffer; 

    protected body Buffer is 
     entry Put(Item : in Integer) when not Is_New is 
     begin 
     Value := Item; 
     Is_New := True; 
     end Put; 
     entry Get(Item : out Integer) when Is_New is 
     begin 
     Item := Value; 
     Is_New := False; 
     end Get; 
    end Buffer; 

    task producer; 
    task body producer is 
     Wait_Limit : constant Natural := 5; 
     Written : Boolean := False; 
    begin 
     for value in 1..15 loop 
     Written := False; 
     for try in 1..Wait_Limit loop 
      Select 
       Buffer.Put(Value); 
       Written := True; 
      or 
       delay 0.5; 
      end select; 
      exit when Written; 
     end loop; 
     if not Written then 
      Put_Line("Producer terminating. Consumer not responding."); 
      exit; 
     end if; 
     end loop; 
    end producer; 

    task consumer; 
    task body consumer is 
     Wait_Limit : Natural := 5; 
     Value_Read : Boolean; 
     The_Value : Integer; 
    begin 
     Loop 
     Value_Read := False; 
     for try in 1..Wait_Limit loop 
      select 
       Buffer.Get(The_Value); 
       Value_Read := True; 
       Put_Line("Consumer read value: " & Integer'Image(The_Value)); 
      or 
       delay 0.5; 
      end select; 
      exit when Value_Read; 
     end loop; 
     if not Value_Read then 
      Put_Line("Consumer terminating. Producer not responding."); 
      exit; 
     end if; 
     end loop; 
    end Consumer; 

begin 
    null; 
end Protected_Producer_Consumer; 

Ada受保护的对象,如上例中的Buffer,提供了自动互斥功能。在上面的例子中,Buffer对象有两个入口Put和Get。 Put条目只能在Buffer内部变量Is_New为False时执行。 Get条目只能在Buffer内部变量Is_New为True时执行。

Producer任务(类似于C++中的线程)包含一个外部循环,该变量将变量“value”设置为第一个1,然后是第二个,依此类推直到15.内部循环尝试将值放入缓冲到Wait_Limit时间。生产者每次设置一个计时器半秒钟,然后再次尝试,如果不成功。如果生产者的Wait_Limit失败,它会写入一条错误消息并终止。

消费者行为与生产者类似。它通过调用Get条目从Buffer读取值。它也会在每次尝试中等待半秒,并在Wait_Limit连续失败后终止以从Buffer读取值。

这个程序的输出是:

Consumer read value: 1 
Consumer read value: 2 
Consumer read value: 3 
Consumer read value: 4 
Consumer read value: 5 
Consumer read value: 6 
Consumer read value: 7 
Consumer read value: 8 
Consumer read value: 9 
Consumer read value: 10 
Consumer read value: 11 
Consumer read value: 12 
Consumer read value: 13 
Consumer read value: 14 
Consumer read value: 15 
Consumer terminating. Producer not responding.