0

ADAの境界バッファ問題に関するこのバリエーションの解決に問題があります(ADAプログラミングでは非常に新しいです)。

バッファに書き込むことができる2つのタスク(AとBと呼びましょう)と、バッファから読み取る1つのタスク(C)があります。タスク A は一度に 2 つの整数をバッファーに挿入し、タスク B は 1 つだけ挿入します。バッファ タスク C からデータを読み取る前に、どちらのタスク (A または B) が最後にデータをバッファに挿入したかを判断する必要があります。

これは、バッファタスクを実装しようとしている方法です。これを行う適切な方法は次のとおりです。

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;によって返される値の両方に使用される型を宣言することだと思います。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;

これは識別された記録です。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

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 に答える
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ステートメントの名前が間違っています。コンパイラは(エヘム)それを受け入れません。

ロジックに関しては、深刻な再考が必要なようです。A または B が書き込むのと同じ順序で C がデータを読み取ることが意図されている場合 (つまり、FIFO キュー)、C に、最後にバッファにデータを挿入したタスクを決定するというステートメントは間違っているようです。代わりに、各バッファーの「要素」が 1 つの整数 (B によって書き込まれる) を持つか、2 つの整数 (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 の数によって、バッファ内の整数の数が異なることを意味することに注意してください。これが要件内で問題ないかどうかはわかりません。

selectGetFlag が返された後、C が常に GetOne または GetTwo を呼び出すことを保証できる限り、ネストされたものを配置した方法は問題ないように見えます。そうしないと、bbuffer が停止し、A と B が二度とバッファーに何も入れることができなくなります。また、バッファが空のときに GetFlag を呼び出した場合に C をブロックする必要があるため、「GetFlag を受け入れる」をwhen count > 0オンにする必要があると思います。いずれにせよ、ロジック全体を作り直す必要があるように見えるので、あまり多くの具体的な提案はしたくありません。

于 2013-07-24T19:27:45.120 に答える