嵌套"然后中止"奇怪的行为

时间:2017-10-11 19:04:25

标签: ada

嵌套"然后中止"在Ada合法建筑?如果是,我可以正确使用它们吗?我有这段代码:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

  task TestTask is
  end TestTask;

  task body TestTask is
  begin
    select
      delay 2.0;
      Put_Line("C"); -- never executed
    then abort
      select
        delay 5.0;
      then abort
        Put_Line("A");
        delay 4.0;
      end select;
      loop
        Put_Line("B");
        delay 10.0;
      end loop;
    end select;
  end TestTask;

begin
  null;
end Main;

我希望这段代码应在2秒后退出。但相反,它会连续打印" B"没有延迟(它忽略了delay 10.0)。它看起来代码的行为方式如下:

  1. 执行Put_Line("A")并等待2秒
  2. 退出内部"然后中止"
  3. 执行循环忽略delay 10.0
  4. 如果不是delay 4.0我们插入delay 1.0(然后在循环中发生中止),程序就能正常工作。我认为这是非常危险的,因为"然后中止"可以在库函数内部,例如:

    procedure Main is
    
      ----- It's function from library -----
    
      procedure Foo is
      begin
        select
          delay 5.0;
        then abort
          Put_Line("A");
          delay 4.0;
        end select;
      end;
    
      ---------------------------------------
    
      task TestTask is
      end TestTask;
    
      task body TestTask is
      begin
        select
          delay 2.0;
          Put_Line("C"); -- never executed
        then abort
          Foo;
          loop
            Put_Line("B");
            delay 10.0;
          end loop;
        end select;
      end TestTask;
    
    begin
      null;
    end Main;
    

    有人可以解释为什么这个程序会以这种奇怪的方式运行吗?

1 个答案:

答案 0 :(得分:3)

A Comparison of the Asynchronous Transfer of Control Features in Ada and the Real-Time Specification中所述,“异步select语句正确处理嵌套的ATC。例如,如果外部触发语句的延迟在内部延迟挂起时到期,则内部延迟将被取消,并且ATC将从内部可挽回的部分颁布......“

以下变体按预期打印ABBBBC。外部触发语句指定五秒超时;嵌套的触发语句指定三秒超时。由于后者的可中止部分仅消耗其第二预算的一秒,因此随后的loop可以在外部超时之前打印四个B.将外部delay更改为1.0,以便重现示例中显示的效果。

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

   task TestTask;

   task body TestTask is
   begin
      select
         delay 5.0;
         Put("C");
      then abort
         select
            delay 3.0;
         then abort
            Put("A");
            delay 1.0;
         end select;
         loop
            Put("B");
            delay 1.0;
         end loop;
      end select;
   end TestTask;

begin
   null;
end Main;