Search code examples
arraysconcurrencyprocedureada

Ada concurrent execution of array of procedure pointers


I'm trying to execute all procedures stored in an array concurrently but with no success. I can execute them sequentially:

with ada.text_io;   -- Tell compiler to use i/o library
use  ada.text_io;   -- Use library routines w/o fully qualified names

with Ada.Numerics.Float_Random; -- Use numerics for the random generation
use ada.Numerics.Float_Random;

procedure Main is

   type Callback_Procedure is access procedure; -- Type that contains a procedure pointer
   type arr is array (Natural range <>) of Callback_Procedure; -- Array starting from 0 toi infinite of procedure pointers
   seed : Generator; -- Seed for the generator

   -- Procedure that will execute "concurrently" the procedures passed in the array
   procedure EjecutarConcurrentemente(procs : in arr ) is
   begin

      for index in 0 .. procs'Last loop

         procs(index).all; -- .all dereferences the pointer so it is the procedure itself (the value pointed by the pointer)

      end loop;      

   end EjecutarConcurrentemente;

   function rndDelay return Duration is
      num : Duration;
   begin
      num := Duration(Random(seed));
      return num * Duration(10);
   end ;


   procedure test0 is
   begin
      delay rndDelay;
      put("test0");
      New_Line;
   end test0;

   procedure test1 is
   begin
      delay rndDelay;
      put("test1");
      New_Line;
   end test1;

   procedure test2 is
   begin
      delay rndDelay;
      put("test2");
      New_Line;
   end test2;

   procedure test3 is
   begin
      delay rndDelay;
      put("test3");
      New_Line;
   end test3;

   procedure test4 is
   begin
      delay rndDelay;
      put("test4");
      New_Line;
   end test4;

   procedure test5 is
   begin
      delay rndDelay;
      put("test5");
      New_Line;
   end test5;

   procs : arr(0..5);

begin

   Reset(seed);

   procs(0) := test0'Access;
   procs(1) := test1'Access;
   procs(2) := test2'Access;
   procs(3) := test3'Access;
   procs(4) := test4'Access;
   procs(5) := test5'Access;

   EjecutarConcurrentemente(procs);

end Main;

The Main procedure body populates an array with 6 procedures declared before and the calls EjecutarConcurrentemente with that array and it must be this new procedure who has to execute the array procedures concurrently.

I've been told to use the Task functionalities, and the testX must be procedures without arguments.

Hope I have explained it well, also I have just started with Ada, so the code will most likely be bad formed.

Thanks.


Solution

  • Here is the code working perfectly:

    with ada.text_io;   -- Tell compiler to use i/o library
    use  ada.text_io;   -- Use library routines w/o fully qualified names
    
    with Ada.Numerics.Float_Random; -- Use numerics for the random generation
    use ada.Numerics.Float_Random;
    
    procedure Main is
    
       type Callback_Procedure is access procedure; -- Type that contains a procedure pointer
       type arr is array (Natural range <>) of Callback_Procedure; -- Array starting from 0 toi infinite of procedure pointers
       seed : Generator; -- Seed for the generator
    
       task type Ex (proc : Callback_Procedure);
       type A is access Ex;
    
       task body Ex is
       begin
          proc.all; --.all dereferences the pointer so it is the procedure itself (the value pointed by the pointer)
       end Ex;
    
       -- Procedure that will execute concurrently the procedures passed in the array
       procedure EjecutarConcurrentemente(procs : in arr ) is
          p : A;
       begin
    
          for index in 0 .. procs'Last loop
    
             p := new Ex(procs(index));
    
          end loop;      
    
       end EjecutarConcurrentemente;
    
       function rndDelay return Duration is
          num : Duration;
       begin
          num := Duration(Random(seed));
          return num * Duration(10);
       end ;
    
    
       procedure test0 is
       begin
          delay rndDelay;
          put("test0");
          New_Line;
       end test0;
    
       procedure test1 is
       begin
          delay rndDelay;
          put("test1");
          New_Line;
       end test1;
    
       procedure test2 is
       begin
          delay rndDelay;
          put("test2");
          New_Line;
       end test2;
    
       procedure test3 is
       begin
          delay rndDelay;
          put("test3");
          New_Line;
       end test3;
    
       procedure test4 is
       begin
          delay rndDelay;
          put("test4");
          New_Line;
       end test4;
    
       procedure test5 is
       begin
          delay rndDelay;
          put("test5");
          New_Line;
       end test5;
    
       procs : arr(0..5);
    
    begin
    
       Reset(seed);
    
       procs(0) := test0'Access;
       procs(1) := test1'Access;
       procs(2) := test2'Access;
       procs(3) := test3'Access;
       procs(4) := test4'Access;
       procs(5) := test5'Access;
    
       EjecutarConcurrentemente(procs);
    
    end Main;
    

    I just make a Task with a procedure pointer as parameter, then in the array loop I do

    new Ex(procs(index));
    

    and it instantly starts a new Task with the given procedure