C 生产者消费者具有例外处理以防止死锁

C++ Producer-Consumer with exception handling to prevent deadlock

本文关键字:处理 死锁 生产者 消费者      更新时间:2023-10-16

在经典生产者 - 消费者问题中,我们让生产者在共享缓冲区满足时等待,而当共享缓冲区为空时,消费者等待。我们有两个POSIX线程,一个生产者和另一个工人,使用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);
    }
}

假定producter()和消费者()正在以独立并发线程运行,当produceItemconsumeItem面对运行时异常时会发生什么,导致线程优雅地处理异常,以便两个线程都可以优雅地出现?在哪里可以将尝试键入良好处理状况?

我使用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受保护的对象,例如上面示例中的缓冲区,提供了自动相互排除。在上面的示例中,缓冲区对象有两个条目,请放置。仅当缓冲区内部变量IS_NEW为false时,才能执行PUT条目。仅当缓冲区内部变量IS_NEW为TRUE时,才能执行GET条目。

生产者任务(类似于C 中的线程)包含一个外循环,将变量"值"设置为第一个1,然后是2个,最多为15。内部循环试图将值放在缓冲区中最高wait_limit时间。每次制作人将计时器设置为一秒钟,然后如果不成功,则再次尝试。如果制作人失败了Wait_limit Times,则会写入错误消息并终止。

消费者行为与生产者相似。它通过调用GET条目从缓冲区读取值。它也会等待每次尝试一半,然后在wait_limit连续读取从缓冲区读取值的失败后终止。

该程序的输出是:

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.