Non Blocking Channel Operations in Ada

Our first example demonstrates non-blocking channel operations. In Ada, we can use the select statement with an else clause to implement non-blocking operations on entry calls and accept statements.

with Ada.Text_IO; use Ada.Text_IO;

procedure Non_Blocking_Operations is
   task type Message_Task is
      entry Send (Msg : in String);
      entry Receive (Msg : out String);
   end Message_Task;

   task type Signal_Task is
      entry Send (Sig : in Boolean);
      entry Receive (Sig : out Boolean);
   end Signal_Task;

   task body Message_Task is
      Message : String(1..20);
      Length : Natural := 0;
   begin
      loop
         select
            accept Send (Msg : in String) do
               Message(1..Msg'Length) := Msg;
               Length := Msg'Length;
            end Send;
         or
            accept Receive (Msg : out String) do
               Msg := Message(1..Length);
            end Receive;
         or
            terminate;
         end select;
      end loop;
   end Message_Task;

   task body Signal_Task is
      Signal : Boolean := False;
   begin
      loop
         select
            accept Send (Sig : in Boolean) do
               Signal := Sig;
            end Send;
         or
            accept Receive (Sig : out Boolean) do
               Sig := Signal;
            end Receive;
         or
            terminate;
         end select;
      end loop;
   end Signal_Task;

   Messages : Message_Task;
   Signals : Signal_Task;
begin
   -- Here's a non-blocking receive. If a message is
   -- available on Messages then the receive will be
   -- executed. If not, it will immediately take the
   -- else clause.
   select
      Messages.Receive (Msg => Message);
      Put_Line ("received message " & Message);
   else
      Put_Line ("no message received");
   end select;

   -- A non-blocking send works similarly. Here the message
   -- cannot be sent to the Messages task, because there's
   -- no receiver ready. Therefore the else clause is selected.
   declare
      Msg : constant String := "hi";
   begin
      select
         Messages.Send (Msg => Msg);
         Put_Line ("sent message " & Msg);
      else
         Put_Line ("no message sent");
      end select;
   end;

   -- We can use multiple alternatives above the else
   -- clause to implement a multi-way non-blocking
   -- select. Here we attempt non-blocking receives
   -- on both Messages and Signals.
   declare
      Message : String(1..20);
      Signal : Boolean;
   begin
      select
         Messages.Receive (Msg => Message);
         Put_Line ("received message " & Message);
      or
         Signals.Receive (Sig => Signal);
         Put_Line ("received signal " & Boolean'Image(Signal));
      else
         Put_Line ("no activity");
      end select;
   end;
end Non_Blocking_Operations;

This Ada code demonstrates non-blocking operations using tasks and the select statement. The Message_Task and Signal_Task types simulate channels, and the select statements with else clauses provide non-blocking behavior.

When you run this program, you’ll see output similar to:

no message received
no message sent
no activity

This output reflects that no messages or signals were available, demonstrating the non-blocking nature of the operations.