2017-12-12 10 views
0

これは、テキストブックであっても、どこにでも提示されているように、Adaの非常に基本的な保護境界バッファです。 (これはもっと大きなものの一部ですが、コードを最小限に単純化して、動作を再現しました)。 私は1つのタスクにそれを供給し、 "メイン"のボディがそれから読んでいるとうまくいくようです。しかし、パターとゲッターという2つのタスクを以下のように使用すると、1st Getでブロックされます。ものではない再評価されているバリアにあなたが見ることができるように、取得(Ada)奇妙な閉塞について2つのタスクで基本保護された有界バッファを取得

$ ./test_buffer 
Putter started 
Put X= 0; First= 0, Last= 0, Count= 0 
Put X= 1; First= 0, Last= 1, Count= 1 
Put X= 2; First= 0, Last= 2, Count= 2 
Put X= 3; First= 0, Last= 3, Count= 3 
Getter started 
Put X= 4; First= 0, Last= 4, Count= 4 
Put X= 5; First= 0, Last= 5, Count= 5 
Put X= 6; First= 0, Last= 6, Count= 6 
Put X= 7; First= 0, Last= 7, Count= 7 
Put X= 8; First= 0, Last= 8, Count= 8 
^C 

が実行されません取得ん、そう:

with Ada.Text_IO;use Ada.Text_IO; 
procedure test_buffer is 

    maxItems : constant Positive := 10; 
    type Index is mod maxItems; 
    maxCount : constant Index := 9; 
    type ItemArray is array(Index) of Integer; 

    protected Buffer is 
     entry Put(X : in Integer); 
     entry Get(X : out Integer); 
    private 
     First, Last, Count : Index := 0; 
     buf : ItemArray; 
    end; 

    protected body Buffer is 
     entry Put(X : in Integer) when Last - First < maxCount is 
     begin 
      Put_Line("Put X="&X'Img & "; First="&First'Img&", Last="&Last'Img&", Count="&Count'Img); 
      buf(Last) := X; 
      Last := Last + 1; 
      Count := Count + 1; 
     end; 
     -- 
     entry Get(X : out Integer) when Last - First > 0 is 
     begin 
      Put_Line("Get X="&X'Img & "; First="&First'Img&", Last="&Last'Img&", Count="&Count'Img); 
      X := buf(First); 
      First := First + 1; 
      Count := Count - 1; 
     end; 
    end; 

    task Putter; 

    task body Putter is 
    begin 
     Put_Line("Putter started"); 
     for i in 0 ..25 loop 
      Buffer.Put(i); 
     end loop; 
    end; 

    task Getter; 
    task body Getter is 
     X : Integer; 
    begin 
     Put_Line("Getter started"); 
     loop 
      Put_Line("requesting X.."); 
      Buffer.Get(X); 
      Put_Line("got X="&X'Img); 
     end loop; 
    end; 

--  X : Integer; 
begin 
--  loop 
--   Buffer.Get(X); 
--   Put_Line("got X="&X'Img); 
--  end loop; 
    Null; 
end test_buffer; 

これは、次のような出力を出してくれる。しかし、本体のコメントを外してタスクをコメントアウトする(またはメインコードのコメントを外してから同時読み込みを行う)と、すべての読み取りと書き込みで正常に処理されます。

ルールを見つけることができません。 (2番目のタスクは外部的なので、いいえ、保護されたオブジェクトの内部呼び出しに対する再評価ではありません)。

私はここで何かが分からないか、これはバグですか?

+2

Debian Stretchのgcc-6(FSF)は私のために働きます(間違いなくバグがないことは証明されません)。お使いのOSとコンパイラのバージョンは何ですか?ここでは、両方のタスクが最初のPutの前に開始され、違いが生じる可能性があります。 –

+0

私のためにも動作します(Debian/Jessieの64ビット版GNAT 4.9.2)。しかし、I/Oコールは「潜在的にブロックされている」ため、保護された操作の中では違法であることに注意してください。 –

+0

いいえ、ここではまだ別のコンピュータでも動作しません。そしてそれはさらに奇妙になる。これがどのように標準的であるかを見ると、GNAT.Bounded_Buffers(その本体にはまったく同じコードがあります)がインスタンス化され、挿入と削除(コードに入れて取得)がすぐに停止します。これは –

答えて

3

ARMセクション9.5.1の状態保護されたアクションの間、潜在的にブロックされている操作を呼び出すための境界エラーです。さらに、文でこれを明確にしています。特定の言語定義のサブプログラムがブロックされている可能性があります。特に、ファイルを(暗黙的にまたは明示的に)操作する言語定義の入出力パッケージのサブプログラムは潜在的にブロックされています。 保護されたエントリ内のPut_Lineプロシージャの呼び出しが潜在的にブロックされているため、エントリから削除する必要があります。

+0

まあ、彼らはそこに(ブロッキングしていた)始まらなかったのです。私はそれらを追加して何が起こっているのかを追跡しました。しかし、この問題は解決されました - 最初は、いくつかの他の例では(これはNullであったのではなく)中断しました私はInterfacesとクラスワイドコールを疑っていました。しかし、それは今でも解決されていますが、かなり不思議な方法ではありますが、ちょうど作業を開始しました(私は差分を実行し、重要な変更はありません)。しかし、Text_IOは火曜日にはブロックされますが、 )。とにかくすべての入力をありがとう! –

関連する問題