冻结Ada任务

时间:2011-11-17 00:14:28

标签: task ada

如何冻结任务?

我的意思是,如果我有任务

task body My_Task is
begin 
  accept Start;
  loop
    Put ("1");
    Put ("2");
    Put ("3");
    ...
    Put ("n");
  end loop;
end My_Task;

有没有办法可以“冻结”当前状态的任务?例如,如果执行完成执行Put ("2");,我怎么能冻结它,以后我可以把它继续?我想要从任务之外以及从外部开始冻结,命令它继续。

更新

如果我有像

这样的规范,我可以肯定实现
type State_Type is
  (RUN,
   FROZEN);

task type My_Task (State : State_Type) is
   entry Start;
end My_Task;

身体

task body My_Task is
begin 
  accept Start;
  loop
    Put ("1");
    Put ("2");
    Put ("3");
    ...
    Put ("n");

    loop 
     if State = RUN then exit; end if;
    end loop;
  end loop;
end My_Task;

但事实并非如此,因为我不得不等待第n个Put指令行(即,任务实际上不会被冻结,因为内部循环将会运行)。

7 个答案:

答案 0 :(得分:5)

您可以使用“选择性接受”来允许您的任务被外部呼叫者(另一个任务或主程序)中断。你不能(轻松地)在执行中的任意点中断任务;相反,任务本身需要确定何时接受入场呼叫。

所以你可能想要替换你的序列

Put("1");
Put("2");
Put("3");
...
Put("n");

通过每次迭代调用Put一次的循环,每次都执行select语句。

这是我刚刚拼凑的演示程序。计数器每秒递增一次(大约)。如果Running为真,则打印计数器值;否则循环静默进行。主程序每3秒钟调用Pause和Resume。

else语句中的select子句会导致它继续执行,如果两个条目都没有被调用。

with Ada.Text_IO; use Ada.Text_IO;
procedure T is

    task Looper is
        entry Pause;
        entry Resume;
    end Looper;

    task body Looper is
        Running: Boolean := True;
        Count: Integer := 0;
    begin
        loop
            select
                accept Pause do
                    Running := False;
                end;
            or
                accept Resume do
                    Running := True;
                end;
            else
                null;
            end select;
            delay 1.0;
            if Running then
                Put_Line("Running, Count = " & Integer'Image(Count));
            end if;
            Count := Count + 1;
        end loop;
    end Looper;

begin -- T
    loop
        delay 3.0;
        Looper.Pause;
        delay 3.0;
        Looper.Resume;
    end loop;
end T;

可能有比这更优雅的方法。自从我真正使用过Ada以来已经很久了。

答案 1 :(得分:4)

哇,有一段时间没见过阿达问题。无论如何,只要您需要暂停任务,就可以使用delaydelay until个保留字。

你要指定一个你想要恢复执行的时间,然后说:

delay <time>

delay until <time>

我不记得确切的细节,但这里是Ada95规范示例:http://www.adaic.org/resources/add_content/docs/95style/html/sec_6/6-1-7.html

答案 2 :(得分:4)

Ada语言背后的设计意图的一个方面是行为是明确的。一个突然发现自己在一个任意点被“冻结”的执行任务没有任何明显的理由 - 任务中没有任何东西会导致这种行为 - 最多会令人不安。如果任务的设计不允许意外的,任意执行暂停,那么可能是一个错误。 (我知道操作系统时间切片在执行程序时强加了这种行为,但这是操作系统的功能,而不是编程语言。)

简而言之,我会严肃质疑依赖外部强制执行任务暂停的设计方法。任务应该知道它自己的状态,因此知道什么时候可以安全地暂停,以及不变量必须保持暂停以确保正确恢复。

答案 3 :(得分:2)

要获得正确中断put("x")序列所需的粒度,您应该将其编写为将其状态保存在task my_task内的过程(知道哪个原子指令已被执行)。

然后我认为您可以在State_Type上使用guard,并且只在未冻结时执行。当然这不会停止任务,它只会保护put("x")序列不被执行(我想这就是你想要的!)

答案 4 :(得分:1)

如果您有一个特定的行,您总是希望您的任务等待,那么解决方案相当简单:只需在其中添加accept语句即可。任务将挂起,直到其他任务调用该条目。

如果您想要概括这个想法(因此可以使多个任务等待,或者多个不同的任务可以安全地执行释放操作),那么将State变量封装在受保护对象中可能会更好(正如NWS建议的那样)。受保护对象的特性被专门用于语言,以便为这样的任务创建同步化对象。

答案 5 :(得分:1)

您在回复其中一条评论时提到,由于某些共享资源,您需要这样做。那么,答案似乎是您希望将该共享资源包装在受保护对象中,并从该任务中调用该受保护对象的过程/条目;当一个任务排队(或执行)一个受保护的对象调用时,它将被置于“阻塞”状态,直到它返回,从而“冻结”进一步的处理。

编辑:添加了一个代码示例。


With
Ada.Text_IO,
Ada.Strings.Fixed,
Ada.Numerics.Float_Random
;

with ada.Integer_Text_IO;
with Ada.Strings;

Use Ada.Numerics.Float_Random;
Procedure Experiment is

   Task Type Testing( Text : Not Null Access String ) is
      end Testing;

   protected Resource is
      procedure Write( Input : In String );
   private
   end Resource;

   Task Body Testing is
      G : Ada.Numerics.Float_Random.Generator;
      D : Duration := Duration( Random(G) );
   Begin
      delay  D;
      Resource.Write( Text.ALL );
   End Testing;

   protected body Resource is
      procedure Write( Input : In String ) is
      begin
         Ada.Text_IO.Put_Line( Input );
      end Write;

   end Resource;

   Function Make(Input : in String) Return Access Testing is
   begin
      Return Result : Access Testing:= New Testing( New String'(Input) );
   end Make;


   TaskList : Array (Positive Range <>) of Access Testing:=
     ( Make("Anger"), Make("Rage"), Make("Joy"), Make("Contentment") );
  Use Ada.Text_IO;
Begin

   Put_Line( "Terminating." );

End Experiment;

注意:put_line的使用在技术上不是线程安全的,[IIRC]可能会阻塞......所以虽然上面应该永远不会死锁,但实际上并没有保证。

答案 6 :(得分:0)

我还得到了Anh Vo in comp.lang.ada (Freezing a task)的答案,其中包括Rendezvous以及任务终止。通过一些调整,它得到:

task type My_Task is
   entry Start;
   entry Pause;
   entry Quit;
   entry Stop;
end My_Task;

-- (...)
task body My_Task is
begin
   Outer_Loop : loop
      select
         accept Start;

         Main_Loop : loop
            select
               accept Pause;

               select
                  accept Quit;
               or
                  accept Stop;
                  exit Outer_Loop;
               or
                  terminate;
               end select;
            or
               accept Stop;
               exit Outer_Loop;
            else
               Put ("Main code here");
               delay MYCYCLE; -- MYCYCLE is 2.0; (whatever)
            end select;
         end loop Main_Loop;
      or
         terminate;
      end select;
  end loop Outer_Loop;
end My_Task;

我承认我认为这个解决方案非常优雅。