Reputation: 99
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
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
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