user1091344
user1091344

Reputation: 740

Tasks are not run concurrently

How can I get these tasks run concurrently, so that the "Hello World from N" messages will be mixed up?

My output looks always like this except that 1, 2 or 3 can be interchanged.

Hello World from 1!
Hello World from 2!
Hello World from 3!

It does not look like the tasks run concurrently. It looks like it run in a chain on a first-come, first-served basis.

main.adb

with Ada.Text_IO;

procedure Main is
   type Runnable_Type is access procedure;

   task type Filter (Runnable_Access : Runnable_Type) is
      entry start;
   end Filter;

   task body Filter is
   begin
      accept start;
      Runnable_Access.all;
   end Filter;

   procedure Run_1 is
   begin
      Ada.Text_IO.Put_Line ("Hello World from 1!");
   end Run_1;

   procedure Run_2 is
   begin
      Ada.Text_IO.Put_Line ("Hello World from 2!");
   end Run_2;

   procedure Run_3 is
   begin
      Ada.Text_IO.Put_Line ("Hello World from 3!");
   end Run_3;

   Filter_1 : Filter (Run_1'Access);
   Filter_2 : Filter (Run_2'Access);
   Filter_3 : Filter (Run_3'Access);
begin
   Filter_1.start;
   Filter_2.start;
   Filter_3.start;
end Main;

Upvotes: 2

Views: 308

Answers (3)

aquilonis
aquilonis

Reputation: 63

As Jack notes, they are run concurrently. Putting a busy-loop in different parts of the Run_* procedures shows this.

with Ada.Text_IO;

procedure Main is
   type Runnable_Type is access procedure;

   task type Filter (Runnable_Access : Runnable_Type) is
      entry start;
   end Filter;

   task body Filter is
   begin
      accept start;
      Runnable_Access.all;
   end Filter;

   procedure Run_1 is
      counter : integer := 0;
   begin
      for i in 1..1000000 loop
         counter := counter + 1;
      end loop;
      Ada.Text_IO.Put_Line ("Hello World from 1a!");
      Ada.Text_IO.Put_Line ("Hello World from 1b!");
      Ada.Text_IO.Put_Line ("Hello World from 1c!");
   end Run_1;

   procedure Run_2 is
      counter : integer := 0;
   begin
      Ada.Text_IO.Put_Line ("Hello World from 2a!");
      for i in 1..1000000 loop
         counter := counter + 1;
      end loop;
      Ada.Text_IO.Put_Line ("Hello World from 2b!");
      Ada.Text_IO.Put_Line ("Hello World from 2c!");
   end Run_2;

   procedure Run_3 is
      counter : integer := 0;
   begin
      Ada.Text_IO.Put_Line ("Hello World from 3a!");
      Ada.Text_IO.Put_Line ("Hello World from 3b!");
      for i in 1..1000000 loop
         counter := counter + 1;
      end loop;
      Ada.Text_IO.Put_Line ("Hello World from 3c!");
   end Run_3;

   Filter_1 : Filter (Run_1'Access);
   Filter_2 : Filter (Run_2'Access);
   Filter_3 : Filter (Run_3'Access);
begin
   Filter_1.start;
   Filter_2.start;
   Filter_3.start;
end Main;

Output is:

Hello World from 2a!
Hello World from 3a!
Hello World from 3b!
Hello World from 2b!
Hello World from 2c!
Hello World from 1a!
Hello World from 1b!
Hello World from 1c!
Hello World from 3c!

Upvotes: 1

ajb
ajb

Reputation: 31699

Using Text_IO.Put_Line will most likely cause the entire line to be written in one operation, although it's plausible that it might be two operations (one to output the characters in the string, and one to output the newline). But the OS call to output the string (possibly without the newline) is probably one call, and the OS operation may be be uninterruptible, or it may go so fast that it would be very difficult to interrupt with a thread switch. In any event, this probably does not output one character at a time. (I'm assuming you're running on a Linux or Windows system or similar, as opposed to an embedded system with a minimal runtime or the like.)

You could output one character at a time yourself:

procedure Output_String (S : String) is
begin
    for I in S'range loop
        Text_IO.Put (S (I));
        --delay 0.0;
    end loop;
    Text_IO.New_Line;
end Output_String;

and then have your Run procedures call this instead of Text_IO.Put_Line. If it doesn't work without delay 0.0, try it with this delay instead, as it may cause the program to look for some other ready task of the same priority to run. I'm not guaranteeing anything, though.

Upvotes: 3

Jack Whitham
Jack Whitham

Reputation: 609

The tasks are running concurrently. They're just not doing enough for this concurrency to be visible. Add more work to each task, e.g. repeatedly printing out a line of text, and you will see it.

Upvotes: 3

Related Questions