我使用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.
什么是你预料之外的本质是什么?如果生产者未能写入共享缓冲区,那么生产者应该处理该异常,并且消费者不应该意识到该异常。如果消费者未能从共享缓冲区读取消息,则消费者应该处理该异常,并且生产者不应该意识到该异常。 –
@JimRogers consumeItem(item)和/或produceItem()可能面临异常 –
这是真的,但两个线程之间唯一的接口是缓冲区。如果生产者遇到异常,则消费者将等待它从异常中恢复。同样,如果消费者遇到异常,生产者将等待消费者从异常中恢复。如果担心生产者或消费者无法从异常中恢复,那么应该等待每个线程等待访问缓冲区。 –