Ada 使用访问类型在受保护对象中调用过程时出现问题

Ada 使用访问类型在受保护对象中调用过程时出现问题,ada,Ada,考虑显示对同一过程的三个不同调用的附加代码。它编译良好,但在执行时挂起。我怀疑有某种锁,但我不明白为什么 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

考虑显示对同一过程的三个不同调用的附加代码。它编译良好,但在执行时挂起。我怀疑有某种锁,但我不明白为什么

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;
在这方面,我们发现

对于在受保护子程序上执行调用,[…]如果调用是内部调用(见9.5),则子程序的主体将与普通子程序调用一样执行。如果调用是外部调用,则子程序主体将作为目标受保护对象上新受保护操作的一部分执行

而在

当名称或前缀表示条目、受保护子程序时,[…]名称或前缀确定目标对象,如下所示:

  • 如果是表示操作声明(或主体)的直接名称或扩展名称,则隐式指定目标对象为立即包含该操作的任务或受保护单元的当前实例;使用这种名称的调用被定义为内部调用
但是,

  • 如果名称或前缀是对受保护子程序值的访问的取消引用(隐式或显式),则目标对象由最初生成访问值的访问属性_引用的前缀确定;使用此名称的调用被定义为外部调用

所以我担心手臂会明确警告你不要做什么
Obj
在进入
Obj时被锁定。Test
,通过
Proc
的外部调用尝试再次锁定。参见。

作为西蒙·赖特答案的附录,我认为

在受保护的操作期间,调用可能阻塞的操作是有界错误。以下被定义为潜在的阻塞操作:

[……]

  • 对与受保护动作具有相同目标对象的受保护子程序(或外部请求)的外部调用
以及

如果检测到有界错误,则会引发程序错误。如果未检测到,有界错误可能会导致死锁或对同一目标对象执行(嵌套)受保护的操作

也适用。如果是这样,则对受保护的子程序执行外部调用可能会导致死锁,但也可能导致程序继续运行(或引发程序错误)

我在GNAT CE 2018 Windows和Linux(Debian)上执行了该程序。Windows上的程序一直运行到最后,但在打印3后挂起到Linux上


详细说明以下注释:您可以使用配置pragma
Detect\u Blocking
对这些潜在阻塞调用进行Ada运行时检查(请参阅)

如果使用GPRbuild,则可以通过放置
pragma Detect\u Blocking来启用检测编码到文件(通常名为
gnat.adc
)中,并通过向编译器包添加
Local\u configuration\u Pragmas
属性,在项目文件中引用此配置文件(另请参见和):


当我编译并运行它时,它就工作了。您使用的是什么版本的工具?更重要的是,我想,@JimRogers,您使用的是什么版本?我知道在您的另一个问题中,您在处理字符串到过程调用的映射。如果这是您仍然感兴趣的内容,您是否希望了解如何将此示例转换为可以使用字符串调用过程的内容?Simon已经回答了“为什么”,所以我基本上是在问,如果你想要这样的东西,更新你的问题,以反映你可能想要什么样的解决方案来解决这个问题。我有一些想法,但它们取决于您的实际需求。我使用的是托管在x86_64-pc-mingw32 GNAT Community 2018(20180523-73)@JimRogers上的GPS 2018(20180523),在Debian stretch上使用相同(但日期为..0525)编译器,在macOS上打印“3”行后挂起,配置pragma
Detect\u Blocking
)导致PE被引发。希望您不介意,我冒昧地编辑了您的链接,直接引用ARM段落到引用(19),将
\p19
添加到URL的末尾。这只适用于2012版ARM(可能还有更高版本)。@SimonWright不,一点也不,谢谢你提供关于URL的提示。对于pragma
Detect_Blocking
:Linux和Windows上的行为相同;出现
程序错误
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;