我在解决ADA中有界缓冲区问题的这种变化时遇到了问题(我在ADA编程中非常新)。
我有两个任务(让我们称之为A和B)可以写入缓冲区和一个从缓冲区(C)读取的任务。任务A当时将两个整数插入缓冲区,而任务B只插入一个整数。在从缓冲区任务C读取数据之前,需要确定哪个任务(A或B)最后将数据插入缓冲区,如果是A则读取最后插入的两个整数,否则只读一个。
这就是我试图实现缓冲任务的方式,我想知道这种方法是否正确:
task bbuffer is
N : constant Integer := 20;
buffer : array(0..N-1) of Integer;
pointer : Integer range 0..N-1;
count : Integer range 0..N;
flag : Integer range 0..1;
begin
loop
select
when count < N =>
accept PutOne(v:in Integer) do
buffer((pointer+count) mod N) := v;
count:=count+1;
end Put;
or
when count < N-1 =>
accept PutTwo(v1:in Integer, v2:in Integer) do
buffer((pointer+count) mod N) := v1;
buffer((pointer+count+1) mod N) := v2;
count:=count+2;
end Put;
or
-- THIS IS WHERE MY PROBLEM IS. Reading from buffer.
-- I first need to determine what to call between ReadOne and ReadTwo
accept GetFlag(f:out Integer) do
f:=flag;
end GetFlag;
select
when count > 0 =>
accept GetOne(v:out Integer) do
v:=buffer(pointer);
pointer := (pointer + 1) mod N;
count := count + 1;
end GetOne;
or
when count > 1 =>
accept GetTwo(v1:out Integer, v2:out Integer)do
v1:=buffer(pointer);
v2:=buffer((pointer+1) mod N);
pointer := (pointer + 2) mod N;
count := count + 2;
end GetTwo;
end select;
end select;
end loop;
end bbuffer;
当A写入缓冲区时设置标志,而当B。
时取消设置感谢您的帮助,谢谢!
答案 0 :(得分:3)
我认为更像Ada的处理方法是声明一个类型,用于缓冲区元素和Get
返回的值;通过这种方式,您可以回避GetFlag
vs GetOne
/ GetTwo
的同步问题,并且可以在实现中使用普通有界缓冲区,而无需担心计数和标记。
元素类型可能如下所示:
type Element (Single_Value : Boolean := True) is record
First : Integer;
case Single_Value is
when True =>
null;
when False =>
Second : Integer;
end case;
end record;
这是一个有区别的记录; Element
Single_Value
= True
的{{1}}没有字段Second
(我提供了Single_Value
的默认值,原因不错,但有很深的理由,值得另一个问题,如果你有兴趣)。
任务规范可能看起来像
task Bounded_Buffer is
entry Put_One (V : Integer);
entry Put_Two (V1, V2 : Integer);
entry Get (Result : out Element);
end Bounded_Buffer;
Put_One
的正文可能包括
Buffer (N) := Element'(Single_Value => True, First => V);
虽然Put_Two
的正文可能包括
Buffer (N) := Element'(Single_Value => False, First => V1, Second => V2);
答案 1 :(得分:1)
好的,首先:在Ada中,必须使用单独的声明和正文声明任务。声明声明了其他任务可能要调用的所有条目。正文包含任务的代码,这就是你上面的内容。您的任务声明如下:
task bbuffer is
entry PutOne (v: in Integer);
entry PutTwo (v1: in Integer; v2: in Integer);
entry GetFlag (f: out Integer);
entry GetOne (v: out Integer);
entry GetTwo (v1: out Integer; v2: out Integer);
end bbuffer;
并且正文将以
开头task body bbuffer is -- note the keyword "body"!!
N : constant integer := 20;
-- and so on
另一个问题:使用分号而不是逗号来分隔条目的参数。这既适用于上面的entry
声明,也适用于您身体中发生的accept
声明。最后,正文中PutOne和PutTwo的accept
语句在end
语句中的名称错误。编译器不会(哼)接受它。
就逻辑而言:它看起来需要一些认真的反思。如果C的意图是按照A或B写入的相同顺序读取数据(即FIFO队列),那么您希望C确定哪个任务 last 将数据插入缓冲区的语句似乎错了。相反,您必须设置缓冲区,以便跟踪每个缓冲区“元素”是否有一个整数(由B编写)或两个整数(由A编写)。我可能会使用记录类型:
type Buffer_Element is record
Num_Integers : Integer range 1 .. 2;
First_Int : Integer;
Second_Int : Integer; -- unused if Num_Integers=1
end record;
Buffer : array (0 .. N - 1) of Buffer_Element;
请注意,这意味着缓冲区中的整数数量取决于调用PutOne和PutTwo的数量。我不知道你的要求是否合适。
您安排嵌套select
的方式看起来没问题,只要您可以保证在GetFlag返回后C始终会调用GetOne或GetTwo。否则,bbuffer可能会失速,A和B再也无法将任何东西放入缓冲区。另外,“接受GetFlag”应该有when count > 0
,因为你希望C阻塞,如果它在缓冲区为空时调用GetFlag,我想。无论如何,我不想给你太多具体的建议,因为看起来整个逻辑需要重新加工。
答案 2 :(得分:1)
如何管理1或2值问题的略有不同的变体 - 使用缓冲区的受保护对象:
type Elements_In_Buffer is range 1 .. 2;
type Element_Array is array (Elements_In_Buffer range <>) of Values;
type Element (Length : Elements_In_Buffer := 1) is
record
Data : Element_Array (1 .. Length);
end record;
protected Buffer is
entry Put (A : in Values);
entry Put (A, B : in Values);
entry Get (Item : out Element);
end Buffer;
我不太确定我是否更喜欢变体记录或带有数组元素的记录。
但受保护对象肯定比实现缓冲区的任务更可取。