2017-12-12 24 views
0

이것은 Ada에서 텍스트 기반의 책들과 마찬가지로 매우 제한적인 보호 된 경계 버퍼입니다. (이것은 더 큰 일의 일부이지만 최소한의 코드로 코드를 단순화하여 동작을 재현했습니다.) 1 개의 작업에 먹이를주고 "기본"본문에서 읽는 것이 좋습니다. 하지만 아래의 두 작업 (Putter 및 Getter)을 사용하면 첫 번째 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; 

이 다음과 같은 출력을 뱉는 다. 그러나 주체의 주석을 제거하고 작업을 주석으로 처리 (또는 주 코드의 주석 처리를 제거하여 동시 읽기를 얻는 경우)하면 모든 읽기 및 쓰기 작업으로 정상적으로 진행됩니다.

규칙을 찾을 수없는 것 같습니다. Get (2 번째 작업은 외부 객체이므로 보호 객체의 내부 호출에 대한 재평가가 아닌)에서 장벽을 막을 수 있습니다.

여기에 명백한 내용이 누락되었거나 버그입니까?

+2

데비안 스트레치의 gcc-6 (FSF)에 대한 저의 작품 (틀림없이, 버그가 없다는 것을 증명하지는 않습니다). OS 및 컴파일러 버전은 무엇입니까? 여기서 두 작업은 첫 번째 Put 전에 시작되어 차이가 발생할 수 있습니다. –

+0

나를 위해 일합니다 (64 비트 데비안/제시에 대한 GNAT 4.9.2). 그러나 I/O 호출은 "잠재적으로 차단"되어 보호 된 작업 내에서 불법임을 알고 있어야합니다. –

+0

아니요, 다른 컴퓨터에서도 계속 작동합니다. 그리고 그것은 더 이상해진다. 이것이 표준적인 방법을 살펴보면, GNAT.Bounded_Buffers (본문에 거의 동일한 코드가 있음)를 인스턴스화하고 삽입 및 제거 (코드에 넣고 가져옴)가 매달려 더 빨리 중단됩니다. 이 : –

답변

3

ARM 섹션 9.5.1에서 상태 보호 된 동작 중에 잠재적으로 차단하는 작업을 호출하는 것은 제한된 오류입니다. 그리고 더 자세히 설명하면 문으로 명확 해집니다. 특정 언어 정의 서브 프로그램이 잠재적으로 차단되어 있습니다. 특히 파일을 조작하는 언어 정의 입출력 패키지 (암시 적 또는 명시 적)의 서브 프로그램은 잠재적으로 블로킹입니다. 보호 된 항목의 Put_Line 프로 시저 호출이 잠재적으로 차단되어 있으므로 항목에서 제거해야합니다.

+0

글쎄, 그들은 (블로킹이 시작될 때) 거기에 없었습니다. 나는이 문제를 해결하기 위해 그것들을 추가했다. 그러나이 문제는 해결되었다 - 먼저 다른 예제 (여기서는 그렇지 않다.이 것은 Null과 관련 있음)에서 문제를 중단하고 차단하지 않았다.하지만 여전히 "큰 프로젝트 "에서 나는 인터페이스와 클래스 - 와이드 호출을 의심했다. 그러나 지금도 매우 신비한 방식으로 해결되었지만 해결되었습니다. (단지 diff를 실행하고 필수 변경 사항은 없습니다.)하지만 실제로 Text_IO는 화요일에 차단하지만 다른 요일에는 차단하지 않습니다.). 어쨌든 모든 입력에 감사드립니다! –