在Ada中嵌套选择

时间:2013-07-24 18:51:18

标签: ada

我在解决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。

时取消设置

感谢您的帮助,谢谢!

3 个答案:

答案 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;

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

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