如何在Ada中创建别名任务?

如何在Ada中创建别名任务?,ada,multitasking,Ada,Multitasking,考虑下面的代码。如何使任务MainTask可别名,并通过access类型进行访问 private with Ada.Text_IO; private with Interfaces.C; private with Interfaces.C.Strings; procedure Main is package Text_IO renames Ada.Text_IO; package C renames Interfaces.C; package CStrings

考虑下面的代码。如何使任务
MainTask
可别名,并通过
access
类型进行访问

 private with Ada.Text_IO;
 private with Interfaces.C;
 private with Interfaces.C.Strings;

 procedure Main is
    package Text_IO renames Ada.Text_IO;
    package C renames Interfaces.C;
    package CStrings renames Interfaces.C.Strings;

    function Puts(S : C.Char_Array) return C.Int;
    pragma Import (C, Puts, "puts");

    package WriteListener is
       type Object is task interface;

       procedure WriteDone (This : in Object; Result : C.Int) is abstract;
    end WriteListener;

    task type Writer (Receiver : access WriteListener.Object'Class) is
       entry Write (Str : in String);
    end Writer;


    task body Writer is
       Result : C.Int;
    begin
       loop
          select
             accept Write (Str : in String) do
                Result := Puts(C.To_C(Str));
             end Write;
             Receiver.WriteDone(Result);
          or
             terminate;
          end select;
       end loop;
    end Writer;

    task MainTask is new WriteListener.Object with
      entry WriteDone (Result : C.Int);
    end MainTask;

    task body MainTask is
       MyWriter :  Writer := new Writer (Receiver => MainTask'Access);
       R : C.Int;
    begin
       R := Puts(C.To_C("Starting asynchronous write"));

       MyWriter.Write("Hello, world!");

       EventLoop: loop
          declare
             TimeToExit : Boolean := False;
          begin

             accept WriteDone (Result : C.Int) do
                R := Puts(C.To_C("Asynchronous write completed"));
                TimeToExit := True;
             end WriteDone;

             exit EventLoop when TimeToExit;
          end;
       end loop EventLoop;
    end MainTask;
 begin
    null;
 end Main;

一种常见的解决方法是声明任务类型,如下所示。也许还有一种方法可以在不分配堆的情况下构造writer任务,但我不知道它的语法

private with Ada.Text_IO;
private with Interfaces.C;
private with Interfaces.C.Strings;

procedure Main is
   package Text_IO renames Ada.Text_IO;
   package C renames Interfaces.C;
   package CStrings renames Interfaces.C.Strings;

   function Puts(S : C.Char_Array) return C.Int;
   pragma Import (C, Puts, "puts");

   package WriteListener is
      type Object is task interface;
      procedure WriteDone (This : in Object; Result : C.Int) is abstract;
   end WriteListener;

   task type Writer (Receiver : not null access WriteListener.Object'Class) is
      entry Write (Str : in String);
   end Writer;

   task body Writer is
      Result : C.Int;
   begin
      loop
         select
            accept Write (Str : in String) do
               Result := Puts(C.To_C(Str));
            end Write;
            Receiver.WriteDone(Result);
         or
            terminate;
         end select;
      end loop;
   end Writer;

   task type MainTask is new WriteListener.Object with
     entry WriteDone (Result : C.Int);
   end MainTask;

   MyMainTask : aliased MainTask;

   task body MainTask is
      MyWriter : not null access Writer := new Writer (Receiver => MyMainTask'Access);
      R : C.Int;
   begin
      R := Puts(C.To_C("Starting asynchronous write"));

      MyWriter.Write("Hello, world!");

      EventLoop: loop
          declare
             TimeToExit : Boolean := False;
          begin

             accept WriteDone (Result : C.Int) do
                R := Puts(C.To_C("Asynchronous write completed"));
                TimeToExit := True;
             end WriteDone;

             exit EventLoop when TimeToExit;
          end;
      end loop EventLoop;
   end MainTask;
begin
   null;
end Main;

一种常见的解决方法是声明任务类型,如下所示。也许还有一种方法可以在不分配堆的情况下构造writer任务,但我不知道它的语法

private with Ada.Text_IO;
private with Interfaces.C;
private with Interfaces.C.Strings;

procedure Main is
   package Text_IO renames Ada.Text_IO;
   package C renames Interfaces.C;
   package CStrings renames Interfaces.C.Strings;

   function Puts(S : C.Char_Array) return C.Int;
   pragma Import (C, Puts, "puts");

   package WriteListener is
      type Object is task interface;
      procedure WriteDone (This : in Object; Result : C.Int) is abstract;
   end WriteListener;

   task type Writer (Receiver : not null access WriteListener.Object'Class) is
      entry Write (Str : in String);
   end Writer;

   task body Writer is
      Result : C.Int;
   begin
      loop
         select
            accept Write (Str : in String) do
               Result := Puts(C.To_C(Str));
            end Write;
            Receiver.WriteDone(Result);
         or
            terminate;
         end select;
      end loop;
   end Writer;

   task type MainTask is new WriteListener.Object with
     entry WriteDone (Result : C.Int);
   end MainTask;

   MyMainTask : aliased MainTask;

   task body MainTask is
      MyWriter : not null access Writer := new Writer (Receiver => MyMainTask'Access);
      R : C.Int;
   begin
      R := Puts(C.To_C("Starting asynchronous write"));

      MyWriter.Write("Hello, world!");

      EventLoop: loop
          declare
             TimeToExit : Boolean := False;
          begin

             accept WriteDone (Result : C.Int) do
                R := Puts(C.To_C("Asynchronous write completed"));
                TimeToExit := True;
             end WriteDone;

             exit EventLoop when TimeToExit;
          end;
      end loop EventLoop;
   end MainTask;
begin
   null;
end Main;

使您的
Main_任务
对象成为类型为
Main_任务
的别名对象

还有,;不要在
Writer
任务上浪费堆分配


还有一件事;记得每次调用时都要检查
put
的结果。

将您的
Main\u任务
对象设置为类型为
Main\u任务
的别名对象

还有,;不要在
Writer
任务上浪费堆分配


还有一件事;记住每次调用时都要检查来自Puts的结果。

以这种方式实现该模式可能会让一些人觉得有点折磨语言。但是,无论如何,如果需要单任务声明类型的别名任务单元,则不需要,因为别名声明需要类型名称,而单任务声明是匿名类型。因此,提出的解决方案使用了一种类型,并将
SomeMainTask
声明为该类型,并使用了别名。这实现了
访问

更一般地说,解决要解决的问题时,如果只有一个任务
MainTask
,那么所有调用方(有限多个)都可以简单地通过它的名称来引用它,从而避免了指向它的需要。关键是在需要的地方使用包含此单一任务的包

另一个要考虑的任务是用ID互相参照的任务;例如,每个任务都可以向某个注册表提供其ID

但是,如果出于其他原因需要某个命名类型的单例任务,则可以完成该任务。一种方法是包装单个任务,并在所有包装对象中使用requeue。但是,OTOH,如果这些任务应该实现一个同步接口,那么它们也必须是任务,所以可能得不到什么好处

下面的大纲重用了原始程序来演示如何进行,尽管只强调了单例性,而不是通信和控制的结构。更可能产生类似于Ada的解决方案的替代方案需要从Ada的消息传递设施的角度重新思考这个问题

package Task_Singleton is
   type TaskWrapper is synchronized new WriteListener.Object with private;
private
   task type TaskWrapper is new WriteListener.Object with
      entry WriteDone (Result : C.Int);
   end TaskWrapper;
   task MainTask is new WriteListener.Object with
      entry WriteDone (Result : C.Int);
   end MainTask;
end Task_Singleton;

package body Task_Singleton is

   task body MainTask is
      R : C.Int;
   begin

   EventLoop: loop
         declare
            TimeToExit : Boolean := False;
         begin

            accept WriteDone (Result : C.Int) do
               R := Puts(C.To_C("Asynchronous write completed"));
               TimeToExit := True;
            end WriteDone;

            exit EventLoop when TimeToExit;
         end;
      end loop EventLoop;
   end MainTask;

   MainWrapper: aliased TaskWrapper;

   task body TaskWrapper is
      MyWriter :  Writer (Receiver => MainWrapper'Access);
      R : C.Int;
   begin
      R := Puts(C.To_C("Starting asynchronous write"));

      MyWriter.Write("Hello, world!");
      loop
         select
            accept WriteDone (Result : C.Int) do
               requeue MainTask.WriteDone;
            end WriteDone;
          or
            terminate;
         end select;
      end loop;

   end Taskwrapper;
end Task_Singleton;

以这种方式实现模式可能会让一些人觉得有点折磨语言。但是,无论如何,如果需要单任务声明类型的别名任务单元,则不需要,因为别名声明需要类型名称,而单任务声明是匿名类型。因此,提出的解决方案使用了一种类型,并将
SomeMainTask
声明为该类型,并使用了别名。这实现了
访问

更一般地说,解决要解决的问题时,如果只有一个任务
MainTask
,那么所有调用方(有限多个)都可以简单地通过它的名称来引用它,从而避免了指向它的需要。关键是在需要的地方使用包含此单一任务的包

另一个要考虑的任务是用ID互相参照的任务;例如,每个任务都可以向某个注册表提供其ID

但是,如果出于其他原因需要某个命名类型的单例任务,则可以完成该任务。一种方法是包装单个任务,并在所有包装对象中使用requeue。但是,OTOH,如果这些任务应该实现一个同步接口,那么它们也必须是任务,所以可能得不到什么好处

下面的大纲重用了原始程序来演示如何进行,尽管只强调了单例性,而不是通信和控制的结构。更可能产生类似于Ada的解决方案的替代方案需要从Ada的消息传递设施的角度重新思考这个问题

package Task_Singleton is
   type TaskWrapper is synchronized new WriteListener.Object with private;
private
   task type TaskWrapper is new WriteListener.Object with
      entry WriteDone (Result : C.Int);
   end TaskWrapper;
   task MainTask is new WriteListener.Object with
      entry WriteDone (Result : C.Int);
   end MainTask;
end Task_Singleton;

package body Task_Singleton is

   task body MainTask is
      R : C.Int;
   begin

   EventLoop: loop
         declare
            TimeToExit : Boolean := False;
         begin

            accept WriteDone (Result : C.Int) do
               R := Puts(C.To_C("Asynchronous write completed"));
               TimeToExit := True;
            end WriteDone;

            exit EventLoop when TimeToExit;
         end;
      end loop EventLoop;
   end MainTask;

   MainWrapper: aliased TaskWrapper;

   task body TaskWrapper is
      MyWriter :  Writer (Receiver => MainWrapper'Access);
      R : C.Int;
   begin
      R := Puts(C.To_C("Starting asynchronous write"));

      MyWriter.Write("Hello, world!");
      loop
         select
            accept WriteDone (Result : C.Int) do
               requeue MainTask.WriteDone;
            end WriteDone;
          or
            terminate;
         end select;
      end loop;

   end Taskwrapper;
end Task_Singleton;

可能会提供一些见解。
private with
对一个过程没有意义。您实际上只使用了
with
的三个软件包中的一个。可能会提供一些见解。
private with
对于一个过程来说没有意义。您实际上只使用了
with
的三个包中的一个
MainTask
是匿名类型,因此无法在类型系统中引用它,就像
Receiver
需要做的那样。我想。(可能就像前一个对象不能重命名一样,参见LRM 8.5(5))。这是很容易更改的。
MainTask
是匿名类型,因此无法在类型系统中引用它,就像
Receiver
需要做的那样。我想。(可能就像前一个对象不能重命名一样,参见LRM 8.5(5))。这是很容易改变的。