ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Ada Real-time Task Scheduling with Priorities

Ada

Goal -- WPM

Ready
Exercise Algorithm Area
1with Ada.Text_IO;
2use Ada.Text_IO;
3with Ada.Real_Time;
4use Ada.Real_Time;
5with Ada.Task_Attributes;
6use Ada.Task_Attributes;
7with Ada.Scheduling;
8use Ada.Scheduling;
9
10package Task_Scheduler_Pkg is
11
12-- Define the maximum number of tasks
13Max_Tasks : constant := 10;
14
15-- Task type with a priority attribute
16task type Prioritized_Task (Task_Name : String) is
17entry Set_Priority (New_Priority : Priority);
18entry Get_Priority (Priority_Value : out Priority);
19entry Execute;
20end Prioritized_Task;
21
22-- Procedure to create and start a new task
23procedure Create_Task (Name : String; Initial_Priority : Priority) return Prioritized_Task'Identity;
24
25-- Procedure to update the priority of an existing task
26procedure Update_Task_Priority (Task_ID : Prioritized_Task'Identity; New_Priority : Priority);
27
28-- Procedure to retrieve the priority of an existing task
29function Get_Task_Priority (Task_ID : Prioritized_Task'Identity) return Priority;
30
31-- Main scheduling loop (simulated)
32procedure Run_Scheduler;
33
34private
35
36-- Internal representation of a task with its attributes
37type Task_Record is record
38ID : Prioritized_Task'Identity;
39Name : String;
40Priority : Priority;
41end record;
42
43-- Array to hold task records
44Tasks : array (1 .. Max_Tasks) of Task_Record;
45Task_Count : Integer := 0;
46
47-- Helper function to find a task by its ID
48function Find_Task (Task_ID : Prioritized_Task'Identity) return Integer;
49
50end Task_Scheduler_Pkg;
51
52package body Task_Scheduler_Pkg is
53
54-- Implementation of the Prioritized_Task task type
55task body Prioritized_Task is
56Current_Priority : Priority := Ada.Scheduling.Default_Priority;
57begin
58loop
59-- Wait for an entry call or the Execute entry
60select
61when Current_Priority /= Ada.Scheduling.Default_Priority =>
62accept Execute;
63-- Simulate task execution
64Put_Line (Task_Name & " executing with priority " & Priority'Image(Current_Priority));
65delay Ada.Real_Time.Milliseconds (100);
66or
67accept Set_Priority (New_Priority : Priority) do
68-- Update the task's priority
69Current_Priority := New_Priority;
70Put_Line (Task_Name & " priority set to " & Priority'Image(Current_Priority));
71-- In a real system, this would involve calling OS-level functions
72-- to change the task's scheduling priority.
73-- For this example, we just update the internal record.
74-- Ada.Scheduling.Set_Priority(Current_Priority);
75end Set_Priority;
76or
77accept Get_Priority (Priority_Value : out Priority) do
78Priority_Value := Current_Priority;
79end Get_Priority;
80or
81terminate;
82end select;
83end loop;
84end Prioritized_Task;
85
86-- Procedure to create a new task
87function Create_Task (Name : String; Initial_Priority : Priority) return Prioritized_Task'Identity is
88begin
89if Task_Count >= Max_Tasks then
90Put_Line ("Error: Max tasks reached.");
91return Prioritized_Task'Identity'First; -- Indicate error
92end if;
93
94Task_Count := Task_Count + 1;
95Tasks(Task_Count).ID := new Prioritized_Task(Name => Name);
96Tasks(Task_Count).Name := Name;
97Tasks(Task_Count).Priority := Initial_Priority;
98
99-- Set the initial priority of the task
100Update_Task_Priority(Tasks(Task_Count).ID, Initial_Priority);
101
102Put_Line ("Task " & Name & " created with initial priority " & Priority'Image(Initial_Priority));
103return Tasks(Task_Count).ID;
104end Create_Task;
105
106-- Procedure to update task priority
107procedure Update_Task_Priority (Task_ID : Prioritized_Task'Identity; New_Priority : Priority) is
108Task_Index : Integer;
109begin
110Task_Index := Find_Task(Task_ID);
111if Task_Index /= 0 then
112-- Call the task's entry to set its priority
113Prioritized_Task(Task_ID).Set_Priority(New_Priority);
114-- Update the internal record as well
115Tasks(Task_Index).Priority := New_Priority;
116else
117Put_Line ("Error: Task not found for priority update.");
118end if;
119end Update_Task_Priority;
120
121-- Function to get task priority
122function Get_Task_Priority (Task_ID : Prioritized_Task'Identity) return Priority is
123Task_Index : Integer;
124Priority_Val : Priority;
125begin
126Task_Index := Find_Task(Task_ID);
127if Task_Index /= 0 then
128-- Call the task's entry to get its priority
129Prioritized_Task(Task_ID).Get_Priority(Priority_Val);
130return Priority_Val;
131else
132Put_Line ("Error: Task not found for priority retrieval.");
133return Ada.Scheduling.Default_Priority; -- Indicate error
134end if;
135end Get_Task_Priority;
136
137-- Simulated scheduler loop
138procedure Run_Scheduler is
139begin
140Put_Line ("Scheduler started.");
141-- In a real RTOS, this would be the main scheduler loop.
142-- For this example, we'll just trigger task execution.
143for I in 1 .. Task_Count loop
144Prioritized_Task(Tasks(I).ID).Execute;
145end loop;
146Put_Line ("Scheduler finished.");
147end Run_Scheduler;
148
149-- Helper function to find a task by its ID
150function Find_Task (Task_ID : Prioritized_Task'Identity) return Integer is
151begin
152for I in 1 .. Task_Count loop
153if Tasks(I).ID = Task_ID then
154return I;
155end if;
156end loop;
157return 0; -- Not found
158end Find_Task;
159
160end Task_Scheduler_Pkg;
Algorithm description viewbox

Ada Real-time Task Scheduling with Priorities

Algorithm description:

This Ada code demonstrates how to manage task priorities in a real-time system. It defines a `Prioritized_Task` type with entries to set and get its priority. The `Task_Scheduler_Pkg` manages a collection of these tasks, allowing for dynamic priority updates. This is essential for real-time scheduling, ensuring that critical tasks receive sufficient CPU time, for example, in a flight control system where urgent commands must be processed before less critical ones.

Algorithm explanation:

The `Task_Scheduler_Pkg` provides functionality to manage tasks with dynamic priorities. The `Prioritized_Task` type has `Set_Priority` and `Get_Priority` entries. The `Task_Record` stores task IDs, names, and their current priorities. `Create_Task` initializes a new task and its record. `Update_Task_Priority` calls the task's `Set_Priority` entry and updates the internal record. `Get_Task_Priority` calls the task's `Get_Priority` entry. The `Find_Task` helper efficiently locates a task by its identity. The `Run_Scheduler` procedure simulates the scheduler's role by triggering task execution. The `select` statement within `Prioritized_Task` allows it to respond to entry calls or execute its `Execute` entry. The `delay` statement simulates work. The time complexity for `Set_Priority` and `Get_Priority` operations, including the internal lookup and the task entry call, is roughly O(N) in the worst case, where N is the number of managed tasks, due to the `Find_Task` linear search. However, the actual scheduler's priority management is typically O(1) or O(log N) depending on the underlying OS scheduler implementation. Space complexity is O(M) where M is `Max_Tasks`, for storing task records.

Pseudocode:

PACKAGE Task_Scheduler_Pkg IS
   Max_Tasks : constant := 10;
   TASK TYPE Prioritized_Task (Task_Name : String) IS
      ENTRY Set_Priority(New_Priority : Priority);
      ENTRY Get_Priority(Priority_Value : out Priority);
      ENTRY Execute;
   END Prioritized_Task;

   PROCEDURE Create_Task(Name : String; Initial_Priority : Priority) RETURN Prioritized_Task'Identity;
   PROCEDURE Update_Task_Priority(Task_ID : Prioritized_Task'Identity; New_Priority : Priority);
   FUNCTION Get_Task_Priority(Task_ID : Prioritized_Task'Identity) RETURN Priority;
   PROCEDURE Run_Scheduler;
PRIVATE
   TYPE Task_Record IS RECORD
      ID : Prioritized_Task'Identity;
      Name : String;
      Priority : Priority;
   END RECORD;
   Tasks : array (1 .. Max_Tasks) of Task_Record;
   Task_Count : Integer := 0;
   FUNCTION Find_Task(Task_ID : Prioritized_Task'Identity) RETURN Integer;
END Task_Scheduler_Pkg;

PACKAGE BODY Task_Scheduler_Pkg IS
   TASK BODY Prioritized_Task IS
      Current_Priority : Priority := Ada.Scheduling.Default_Priority;
   BEGIN
      LOOP
         SELECT
            WHEN Current_Priority /= Ada.Scheduling.Default_Priority =>
               ACCEPT Execute;
               -- Simulate execution
            OR
               ACCEPT Set_Priority(New_Priority : Priority) DO
                  Current_Priority := New_Priority;
               END Set_Priority;
            OR
               ACCEPT Get_Priority(Priority_Value : out Priority) DO
                  Priority_Value := Current_Priority;
               END Get_Priority;
            OR TERMINATE;
         END SELECT;
      END LOOP;
   END Prioritized_Task;

   FUNCTION Create_Task(Name : String; Initial_Priority : Priority) RETURN Prioritized_Task'Identity IS
   BEGIN
      IF Task_Count >= Max_Tasks THEN RETURN Prioritized_Task'Identity'First; END IF;
      Task_Count := Task_Count + 1;
      Tasks(Task_Count).ID := new Prioritized_Task(Name => Name);
      Tasks(Task_Count).Name := Name;
      Tasks(Task_Count).Priority := Initial_Priority;
      Update_Task_Priority(Tasks(Task_Count).ID, Initial_Priority);
      RETURN Tasks(Task_Count).ID;
   END Create_Task;

   PROCEDURE Update_Task_Priority(Task_ID : Prioritized_Task'Identity; New_Priority : Priority) IS
      Task_Index : Integer;
   BEGIN
      Task_Index := Find_Task(Task_ID);
      IF Task_Index /= 0 THEN
         Prioritized_Task(Task_ID).Set_Priority(New_Priority);
         Tasks(Task_Index).Priority := New_Priority;
      END IF;
   END Update_Task_Priority;

   FUNCTION Get_Task_Priority(Task_ID : Prioritized_Task'Identity) RETURN Priority IS
      Task_Index : Integer;
      Priority_Val : Priority;
   BEGIN
      Task_Index := Find_Task(Task_ID);
      IF Task_Index /= 0 THEN
         Prioritized_Task(Task_ID).Get_Priority(Priority_Val);
         RETURN Priority_Val;
      ELSE RETURN Ada.Scheduling.Default_Priority; END IF;
   END Get_Task_Priority;

   PROCEDURE Run_Scheduler IS
   BEGIN
      FOR I IN 1 .. Task_Count LOOP
         Prioritized_Task(Tasks(I).ID).Execute;
      END LOOP;
   END Run_Scheduler;

   FUNCTION Find_Task(Task_ID : Prioritized_Task'Identity) RETURN Integer IS
   BEGIN
      FOR I IN 1 .. Task_Count LOOP
         IF Tasks(I).ID = Task_ID THEN RETURN I; END IF;
      END LOOP;
      RETURN 0;
   END Find_Task;
END Task_Scheduler_Pkg;