LaTeXEnthusiast
LaTeXEnthusiast

Reputation: 99

Can we run every task from a pool not in a synchronous manner?

I am new to Ada.

I have declared my new task type and I stored three of them in a pool. Then, I want to run every task in a loop.

The expected behavior is that all of them are executed at the same time.

The reality is, they are executed one-after-another. So, no sooner is tasks(2) executed than tasks(1) has terminated. In fact, task(2) will never have been executed since it terminaes due to the select constraints.

My code:

with Counter;
procedure Main is
    task type CounterTask is
        entry Execute(t:in Counter.Timeout; d:in Duration);
    end CounterTask;

    task body CounterTask is
        begin MyLoop: loop 
            select
                accept Execute(t:in Counter.Timeout;d:in Duration) do
                    Counter.Run(t, d);
                end Execute;
            or
                delay 2.0;
                exit;
            end select;
        end loop MyLoop;
    end CounterTask;
    tasks:Array(1..3) of CounterTask;
begin
    for i in Integer range 1..3 loop
        tasks(i).Execute(Counter.Timeout(10*i), Duration(0.5 * i));
    end loop;
end Main;

Any hints or ideas will be most welcome!

Upvotes: 2

Views: 65

Answers (2)

DeeDee
DeeDee

Reputation: 5941

Apart from taking Counter.Run out of the accept block (as was just stated by Simon Wright), you might also want to consider using a synchronization barrier (see also ARM D.10.1):

with Counter;
with Ada.Synchronous_Barriers;

procedure Main is

  use Ada.Synchronous_Barriers;

  Num_Tasks : Positive := 3;

  Sync : Synchronous_Barrier (Num_Tasks);

  task type Counter_Task is
      entry Execute (T : in Counter.Timeout; D : in Duration);
  end Counter_Task;

  task body Counter_Task is
      Notified     : Boolean;
      The_Timeout  : Counter.Timeout;
      The_Duration : Duration;
  begin
      MyLoop : loop
        select

            accept Execute (T : in Counter.Timeout; D : in Duration) do
              The_Timeout  := T;
              The_Duration := D;
            end Execute;

            --  Synchronize tasks: wait until all 3 tasks have arrived at this point.
            Wait_For_Release (Sync, Notified);

            Counter.Run (The_Timeout, The_Duration);    
        or
            delay 2.0;
            exit;
        end select;
      end loop MyLoop;
  end Counter_Task;

  Tasks : array (1 .. Num_Tasks) of Counter_Task;

begin
  for K in Tasks'Range loop
      Tasks (K).Execute
        (Counter.Timeout (K * 10),
         Duration (Duration (0.5) * K));
  end loop;
end Main;

Upvotes: 2

Simon Wright
Simon Wright

Reputation: 25501

When your main program calls the accept statement

accept Execute(t:in Counter.Timeout;d:in Duration) do
   Counter.Run(t, d);
end Execute;

it is blocked until the end Execute. You don’t show Counter.Run, but I guess that there’s a delay t (or d?) in there.

You need to copy Execute’s parameters to local task variables within the accept statement, and only then call Counter.Run; that way, both the main program and the Countertask are free to proceed.

task body CounterTask is
   Timeout : Counter.Timeout;
   Dur : Duration;
begin 
MyLoop:
   loop 
      select
         accept Execute(t:in Counter.Timeout;d:in Duration) do
            Timeout := T;
            Dur := D;
         end Execute;
         Counter.Run (Timeout, Dur);
      or
         delay 2.0;
         exit;
      end select;
   end loop MyLoop;
end CounterTask;

Upvotes: 6

Related Questions