Timers in Ada

Our example demonstrates how to use timers in Ada. Timers allow us to execute code at a specific point in the future or repeatedly at some interval. We’ll focus on single-event timers in this example.

with Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;

procedure Timer_Example is
   -- Define a task type for our timer
   task type Timer (Duration_Sec : Positive) is
      entry Start;
      entry Stop;
   end Timer;

   task body Timer is
      Trigger_Time : Time;
      Stopped : Boolean := False;
   begin
      accept Start;
      Trigger_Time := Clock + Seconds (Duration_Sec);
      select
         accept Stop do
            Stopped := True;
         end Stop;
      or
         delay until Trigger_Time;
         if not Stopped then
            Ada.Text_IO.Put_Line ("Timer fired after" & Duration_Sec'Image & " seconds");
         end if;
      end select;
   end Timer;

   -- Create two timer instances
   Timer1 : Timer (Duration_Sec => 2);
   Timer2 : Timer (Duration_Sec => 1);
begin
   -- Start Timer1 and wait for it to complete
   Timer1.Start;
   delay 2.1;  -- Wait slightly longer than the timer duration
   Ada.Text_IO.Put_Line ("Timer 1 completed");

   -- Start Timer2 but stop it before it fires
   Timer2.Start;
   delay 0.5;  -- Wait for a short time
   Timer2.Stop;
   Ada.Text_IO.Put_Line ("Timer 2 stopped");

   -- Wait to ensure Timer2 doesn't fire
   delay 1.0;
end Timer_Example;

In this Ada example, we use tasks to implement timer functionality:

  1. We define a Timer task type that takes a duration in seconds as a discriminant.

  2. The Timer task has two entries: Start to begin the timer and Stop to cancel it before it fires.

  3. We create two timer instances: Timer1 set for 2 seconds and Timer2 set for 1 second.

  4. We start Timer1 and wait for it to complete. This is similar to the blocking nature of the Go timer.

  5. We then start Timer2 but stop it before it has a chance to fire, demonstrating how to cancel a timer.

  6. The select statement in the task body allows us to either accept a Stop entry call or wait until the trigger time, whichever comes first.

To run this program, save it as timer_example.adb and compile it using an Ada compiler:

$ gnatmake timer_example.adb
$ ./timer_example
Timer 1 completed
Timer 2 stopped

This output shows that the first timer completed as expected, while the second timer was successfully stopped before it could fire.

Ada’s tasking model provides a different approach to concurrency compared to Go’s goroutines, but it allows us to achieve similar functionality with timers and cancellation.