【问题标题】:Problem calling procedure in protected object using access type使用访问类型在受保护对象中调用过程的问题
【发布时间】:2019-02-17 03:32:39
【问题描述】:

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

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;

【问题讨论】:

  • 它在我编译和运行它时工作。您使用的是什么版本的工具?
  • 更重要的是,我想,@JimRogers,使用的是什么版本?
  • 我知道在您的其他问题之一中,您正在处理字符串到过程调用的映射。如果那是您仍然感兴趣的东西,您想知道如何将这个示例转换为可以使用字符串调用过程的东西吗?西蒙已经回答了“为什么”,所以我基本上是在问,如果你想要这样的东西,更新你的问题以反映你可能想要什么样的解决方案来解决这个问题。我有一些想法,但它们取决于您的实际要求。
  • 我正在使用 x86_64-pc-mingw32 GNAT Community 2018 (20180523-73) 上托管的 GPS 2018 (20180523)
  • @JimRogers,在 Debian 拉伸上使用相同(但日期为 ..0525)的编译器,它在打印“3”行后挂起

标签: ada


【解决方案1】:

ARM 9.5.1(3),我们发现

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

ARM 9.5(2,3)

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

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

但是,在(5)

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

所以恐怕 ARM 会明确警告您要做什么; Obj 在进入Obj.Test 时被锁定,通过Proc 的外部调用尝试再次获取锁定。见DeeDee’s answer

【讨论】:

    【解决方案2】:

    作为 Simon Wright 答案的补充,我认为 ARM 9.5.1 (15)

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

    [...]

    • 对受保护子程序(或外部重新队列)的外部调用,其目标对象与受保护操作的目标对象相同;

    ARM 9.5.1 (17)

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

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

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


    详细说明下面的 cmets:您可以使用配置编译指示 Detect_Blocking 让 Ada 运行时检查这些潜在的阻塞调用(请参阅 ARM H.5)。

    如果您使用 GPRbuild,则可以通过将 pragma Detect_Blocking; 放入文件(通常名为 gnat.adc)来启用检测,并通过将 Local_Configuration_Pragmas 属性添加到编译器来在您的项目文件中引用此配置文件包(另见herehere):

    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;
    

    【讨论】:

    • 在 macOS 上,配置编译指示 Detect_Blocking (ARM 9.5.1(22.1)) 导致 PE 被提升。
    • 希望您不介意,我冒昧地编辑了您的链接,直接引用了 ARM 段落 - 参考 (19),在 URL 末尾添加 #p19。这仅适用于 2012 ARM(可能还有更高版本)。
    • @SimonWright 不,一点也不,感谢有关 URL 的提示。对于 pragma Detect_Blocking:在 Linux 和 Windows 上的行为相同;提出了Program_Error
    猜你喜欢
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 2014-10-15
    • 2018-03-21
    相关资源
    最近更新 更多