Проблема вызова процедуры в защищенном объекте с использованием типа доступа - PullRequest
0 голосов
/ 15 февраля 2019

Рассмотрим прикрепленный код, показывающий три разных вызова к одной и той же процедуре.Он хорошо компилируется, но зависает во время выполнения.Я подозреваю о какой-то блокировки, но не могу понять почему.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
procedure Main is

   type A_Proc is access protected procedure (B: in out Integer);

   protected Obj is
      procedure Inc (B: in out Integer);
      procedure Test (B: in out Integer);
   end Obj;
   protected body Obj is
      procedure Inc (B: in out Integer) is
      begin
         B:=B+1;
      end Inc;
      procedure Test (B: in out Integer) is
         Proc : A_Proc:=Inc'Access;
      begin
         Proc.all (B);
      end Test;
   end Obj;

   B : Integer:=1;

   Proc : A_Proc:=Obj.Inc'Access;
begin
   Put_Line(B'Image);
   Obj.Inc (B);
   Put_Line(B'Image);
   Proc.all (B);
   Put_Line(B'Image);
   Obj.Test (B);
   Put_Line(B'Image);
   Put_Line("The End");
end Main;

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

В качестве дополнения к ответу Саймона Райта я считаю, что ARM 9.5.1 (15) ,

Во время защищенного действия это ограниченная ошибка длявызвать операцию, которая потенциально блокирует.Следующие элементы определены как потенциально блокирующие операции:

[...]

  • внешний вызов защищенной подпрограммы (или внешний запрос) с тем же целевым объектом, что изащищенного действия;

и ARM 9.5.1 (17) ,

Если обнаружена ограниченная ошибка, возникает Program_Error.Если не обнаружено, ограниченная ошибка может привести к взаимоблокировке или (вложенному) защищенному действию для того же целевого объекта.

также применимо.Если это так, то выполнение внешнего вызова для защищенной подпрограммы может привести к взаимоблокировке, но может также привести к продолжению работы программы (или к возникновению ошибки Program_Error).

Я выполнил программу на GNAT CE 2018 как для Windows, так и для Linux (Debian).Программа в Windows работает до конца, но зависает в Linux после печати 3.


Для уточнения комментариев ниже: вы можете использовать конфигурационную прагму Detect_Blocking, чтобы проверить время выполнения Ada дляэти потенциально блокирующие вызовы (см. ARM H.5 ).

Если вы используете GPRbuild, то вы можете включить обнаружение, поместив pragma Detect_Blocking; в файл (обычно с именем gnat.adc)и сослаться на этот файл конфигурации в файле проекта, добавив атрибут Local_Configuration_Pragmas в пакет компилятора (см. также здесь и здесь ):

project Default is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");

   package Compiler is
      for Local_Configuration_Pragmas use "gnat.adc";
   end Compiler;

end Default;
0 голосов
/ 16 февраля 2019

В ARM 9.5.1 (3) , мы находим

Для выполнения вызова в защищенной подпрограмме, [...] Если вызов являетсявнутренний вызов (см. 9.5), тело подпрограммы выполняется как для обычного вызова подпрограммы.Если вызов является внешним вызовом, то тело подпрограммы выполняется как часть нового защищенного действия на целевом защищенном объекте

и ARM 9,5 (2,3) ,

Когда имя или префикс обозначает запись, защищенную подпрограмму, [...] имя или префикс определяет целевой объект следующим образом:

  • Если это прямое имя или расширенное имя, которое обозначает объявление (или тело) операции, то целевой объект неявно указывается как текущий экземпляр задачи или защищенного модуля, немедленно включающего операцию;вызов с таким именем определяется как внутренний вызов

, но в (5) ,

  • Если имя или префикс является разыменовкой (явной или неявной) значения доступа к защищенной подпрограмме, то целевой объект определяется по префиксу Access attribute_reference, который изначально создал значение доступа;вызов с таким именем определяется как внешний вызов

, поэтому я боюсь, что ARM явно предупреждает о том, что вы пытаетесь сделать;Obj блокируется при входе в Obj.Test, и внешний вызов через Proc пытается снова взять блокировку.См. Ответ DeeDee .

...