C ++ Producer-Consumer,具有异常处理功能,可防止死锁

时间:2016-12-14 10:16:57

标签: c++ multithreading semaphore producer-consumer

classical producer-consumer problem中,我们让生产者等待共享缓冲区已满并且消费者在共享缓冲区为空时等待。我们有两个posix线程,一个生产者和另一个worker,使用sem_wait和sem_post为空信号量和完整信号量(两者都计算信号量)相互同步。因此,生产者 - 消费者代码的信号量实现如下所示:

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);
    }
}

假设producer()和consumer()在独立并发线程中运行,当produceItemconsumeItem面临运行时异常导致线程正常处理异常时会发生什么,以便线程可以优雅地出来? 在哪里放置try-catch以妥善处理这种情况?

1 个答案:

答案 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”设置为first 1,然后设置为2,依此类推,直到15.内部循环尝试将值放入Buffer中最多Wait_Limit次。每次Producer将计时器设置为半秒,然后如果不成功则再次尝试。如果生产者在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.