1

Is there an way To run an Ada Task in Backround ?

package body Main is

   task type Background is end Background;

   task body Background is
         
   begin
        
      loop
         
         delay 1.0;
         Do_Stuff;
         
      end loop;
         
   end Background;

   
   procedure Enable is
      
     B_TASK:Background;
   begin 
      
      --Please do not wait here..
      null;
      
   end Enable;
   

end Main;

2 Answers 2

4

Your question is a little vague (the meaning of "background" is unclear), but from the code example it seems you want a procedure Enable such that when it is called, a new "Background" task is started and Enable can return to its caller without waiting for the new task to terminate, leaving the new task running concurrently with the original task that called Enable.

You can create such "background" tasks by creating them dynamically, using an access type and the "new" keyword:

type Background_Ref is access Background;

procedure Enable
is
    B : Background_Ref := new Background;
    -- A new Background task is created and starts running
    -- concurrently with the present task.
begin
    null;
    -- This does not wait for the new task to terminate.
end Enable;

Note that in this case the program itself will wait for all created background tasks to terminate, before the whole program terminates.

6
  • this doses the trick..
    – mcxbain
    Commented Sep 1, 2023 at 9:51
  • @NiklasHolsti just wondering if I could confirm, the reason the "main" subprogram doesn't terminate is because it is the "master" of the background task (i.e. it's the task where the task access type is declared), is that correct? One thing I was wondering, is how come the scoping rules work? i.e. the task object (B) has a shorter lifespan than its access type which is the scope of "main" (as it gets out of scope when the Enableprocedure returns) Wouldn't that be prohibited under the usual access-type rules?
    – Sidisyom
    Commented Sep 3, 2023 at 8:54
  • When you create a task with an allocator and a named access type (as here), the task depends on each "master" that includes the elaboration of the declaration of the ultimate ancestor of the given access type (RM 9.3(2/4)). In this case I think the access type is elaborated in the package Main, and that elaboration is done by the environment task, so I think that it is actually the environment task that waits for the background tasks to terminate, in principle after the main subprogram returns to where the environment task called it. Commented Sep 4, 2023 at 10:43
  • You have the access-type rules backwards: an object can certainly have a shorter lifetime than its type; but not the other way around: the type must live at least as long as the object. In my example code, I intended the access type to be declared in package Main. If instead the access type were declared (and thus elaborated) in procedure Enable, now the execution of Enable would be one of the masters described in RM 9.3(2/4), and therefore Enable would not return until the background task has terminated. Commented Sep 4, 2023 at 10:51
  • 1
    You are very welcome, and the article you read is not wrong, but there is a delicate point of Ada RM terminology: the article is talking about things like packages etc. In Ada RM terms, those are "master constructs", while the term "master", by itself, refers to the /execution/ of a master construct. For example, if we are talking about termination of masters, it makes no sense to talk about the "termination of a package", but it does make sense to talk about the termination of the task whose execution elaborated the package. Commented Sep 5, 2023 at 20:51
2

You have not described what you mean by "background".

Here is a simple Ada program where the "background" task runs as I think you want a background task to run.

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   task background;

   task body background is
   begin
      for I in 1 .. 10 loop
         Put_Line ("Background:" & I'Image);
         delay 1.5;
      end loop;
   end background;

begin
   for I in 1 .. 10 loop
      Put_Line ("Main" & I'Image);
      delay 1.0;
   end loop;
end Main;

A sample output from this program is:

Main 1
Background: 1
Main 2
Background: 2
Main 3
Background: 3
Main 4
Main 5
Background: 4
Main 6
Background: 5
Main 7
Main 8
Background: 6
Main 9
Background: 7
Main 10
Background: 8
Background: 9
Background: 10

The main task clearly works independently of the background task. Since both tasks are in the same process the process must not terminate before both tasks terminate.

If you want the main task to wait for the completion of the background task before it terminates, the background task must be created in an inner block of the main task.

with Ada.Text_IO; use Ada.Text_IO;

procedure joined_task is
begin
   -- create an inner block
   declare
      task background;

      task body background is
      begin
         for I in 1 .. 10 loop
            Put_Line ("Background:" & I'Image);
            delay 1.5;
         end loop;
      end background;
   begin
      null;
   end;
   for I in 1 .. 10 loop
      Put_Line ("Main:" & I'Image);
      delay 1.0;
   end loop;
end joined_task;

The output of this program is:

Background: 1
Background: 2
Background: 3
Background: 4
Background: 5
Background: 6
Background: 7
Background: 8
Background: 9
Background: 10
Main: 1
Main: 2
Main: 3
Main: 4
Main: 5
Main: 6
Main: 7
Main: 8
Main: 9
Main: 10

The main task waited for the background task to complete before executing its loop. In the first example both tasks executed in an overlapping manner, while the second example demonstrated how the main task waited for completion of its inner block before proceeding. The second example is functionally similar to using the join command in Java or in C or C++ thread libraries.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.