0

我在解决 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 时取消设置。

我将不胜感激任何帮助,谢谢!

4

3 回答 3

3

我认为一种更类似于 Ada 的处理方式是声明一个用于缓冲区元素和由Get;返回的值的类型。这样,您就可以回避GetFlagvs 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;

这是一项歧视性记录;Elementwith Single_Value=True没有字段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);
于 2013-07-24T20:31:33.443 回答
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于您身体中出现的陈述。最后,您accept在正文中对 PutOne 和 PutTwo 的语句在end语句上的名称错误。编译器不会(咳咳)接受这一点。

至于逻辑:看起来它需要一些认真的重新思考。如果意图是让 C 以与 A 或 B 写入数据的顺序相同的顺序读取数据(即 FIFO 队列),那么您希望 C 确定哪个任务最后将数据插入缓冲区的语句似乎是错误的。相反,您必须设置缓冲区,以便跟踪每个缓冲区“元素”是有一个整数(由 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看起来不错,只要您可以保证 C 在 GetFlag 返回后始终调用 GetOne 或 GetTwo 即可。否则,bbuffer 可能会停止,A 和 B 再也无法在缓冲区中放入任何内容。另外,“接受GetFlag”应该有when count > 0它,因为我认为如果在缓冲区为空时调用GetFlag,您希望C阻塞。无论如何,我不想给你太多具体的建议,因为看起来整个逻辑都需要重新设计。

于 2013-07-24T19:27:45.120 回答
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;

我不太确定我更喜欢变体记录还是带有数组元素的记录。

但是受保护的对象绝对比实现缓冲区的任务更可取。

于 2013-07-25T13:19:41.223 回答