Tasking

Display Service

Goal: create a simple service that displays messages to the user.

Steps:

  1. Implement the Display_Services package.

    1. Declare the task type Display_Service.

    2. Implement the Display entry for strings.

    3. Implement the Display entry for integers.

Requirements:

  1. Task type Display_Service uses the Display entry to display messages to the user.

  2. There are two versions of the Display entry:

    1. One that receives messages as a string parameter.

    2. One that receives messages as an Integer parameter.

  3. When a message is received via a Display entry, it must be displayed immediately to the user.

    
        
    
    
    
        
package Display_Services is end Display_Services;
package body Display_Services is end Display_Services;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Display_Services; use Display_Services; procedure Main is type Test_Case_Index is (Display_Service_Chk); procedure Check (TC : Test_Case_Index) is Display : Display_Service; begin case TC is when Display_Service_Chk => Display.Display ("Hello"); delay 0.5; Display.Display ("Hello again"); delay 0.5; Display.Display (55); delay 0.5; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Event Manager

Goal: implement a simple event manager.

Steps:

  1. Implement the Event_Managers package.

    1. Declare the task type Event_Manager.

    2. Implement the Start entry.

    3. Implement the Event entry.

Requirements:

  1. The event manager has a similar behavior as an alarm

    1. The sole purpose of this event manager is to display the event ID at the correct time.

    2. After the event ID is displayed, the task must finish.

  2. The event manager (Event_Manager type) must have two entries:

    1. Start, which starts the event manager with an event ID;

    2. Event, which delays the task until a certain time and then displays the event ID as a user message.

  3. The format of the user message displayed by the event manager is Event #<event_id>.

    1. You should use Natural'Image to display the ID (as indicated in the body of the Event_Managers package below).

Remarks:

  1. In the Start entry, you can use the Natural type for the ID.

  2. In the Event entry, you should use the Time type from the Ada.Real_Time package for the time parameter.

  3. Note that the test application below creates an array of event managers with different delays.

    
        
    
    
    
        
package Event_Managers is end Event_Managers;
package body Event_Managers is -- Don't forget to display the event ID: -- -- Put_Line ("Event #" & Natural'Image (Event_ID)); end Event_Managers;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Event_Managers; use Event_Managers; with Ada.Real_Time; use Ada.Real_Time; procedure Main is type Test_Case_Index is (Event_Manager_Chk); procedure Check (TC : Test_Case_Index) is Ev_Mng : array (1 .. 5) of Event_Manager; begin case TC is when Event_Manager_Chk => for I in Ev_Mng'Range loop Ev_Mng (I).Start (I); end loop; Ev_Mng (1).Event (Clock + Seconds (5)); Ev_Mng (2).Event (Clock + Seconds (3)); Ev_Mng (3).Event (Clock + Seconds (1)); Ev_Mng (4).Event (Clock + Seconds (2)); Ev_Mng (5).Event (Clock + Seconds (4)); end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Generic Protected Queue

Goal: create a queue container using a protected type.

Steps:

  1. Implement the generic package Gen_Queues.

    1. Declare the protected type Queue.

    2. Implement the Empty function.

    3. Implement the Full function.

    4. Implement the Push entry.

    5. Implement the Pop entry.

Requirements:

  1. These are the formal parameters for the generic package Gen_Queues:

    1. a formal modular type;

      • This modular type should be used by the Queue to declare an array that stores the elements of the queue.

      • The modulus of the modular type must correspond to the maximum number of elements of the queue.

    2. the data type of the elements of the queue.

      • Select a formal parameter that allows you to store elements of any data type in the queue.

  2. These are the operations of the Queue type:

    1. Function Empty indicates whether the queue is empty.

    2. Function Full indicates whether the queue is full.

    3. Entry Push stores an element in the queue.

    4. Entry Pop removes an element from the queue and returns the element via output parameter.

Remarks:

  1. In this exercise, we create a queue container by declaring and implementing a protected type (Queue) as part of a generic package (Gen_Queues).

  2. As a bonus exercise, you can analyze the body of the Queue_Tests package and understand how the Queue type is used there.

    1. In particular, the procedure Concurrent_Test implements two tasks: T_Producer and T_Consumer. They make use of the queue concurrently.

    
        
    
    
    
        
package Gen_Queues is end Gen_Queues;
package body Gen_Queues is end Gen_Queues;
package Queue_Tests is procedure Simple_Test; procedure Concurrent_Test; end Queue_Tests;
with Ada.Text_IO; use Ada.Text_IO; with Gen_Queues; package body Queue_Tests is Max : constant := 10; type Queue_Mod is mod Max; procedure Simple_Test is package Queues_Float is new Gen_Queues (Queue_Mod, Float); Q_F : Queues_Float.Queue; V : Float; begin V := 10.0; while not Q_F.Full loop Q_F.Push (V); V := V + 1.5; end loop; while not Q_F.Empty loop Q_F.Pop (V); Put_Line ("Value from queue: " & Float'Image (V)); end loop; end Simple_Test; procedure Concurrent_Test is package Queues_Integer is new Gen_Queues (Queue_Mod, Integer); Q_I : Queues_Integer.Queue; task T_Producer; task T_Consumer; task body T_Producer is V : Integer := 100; begin for I in 1 .. 2 * Max loop Q_I.Push (V); V := V + 1; end loop; end T_Producer; task body T_Consumer is V : Integer; begin delay 1.5; while not Q_I.Empty loop Q_I.Pop (V); Put_Line ("Value from queue: " & Integer'Image (V)); delay 0.2; end loop; end T_Consumer; begin null; end Concurrent_Test; end Queue_Tests;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Queue_Tests; use Queue_Tests; procedure Main is type Test_Case_Index is (Simple_Queue_Chk, Concurrent_Queue_Chk); procedure Check (TC : Test_Case_Index) is begin case TC is when Simple_Queue_Chk => Simple_Test; when Concurrent_Queue_Chk => Concurrent_Test; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;