Introducción

Los sistemas en tiempo real son aquellos que deben cumplir con restricciones temporales estrictas. En estos sistemas, la corrección del sistema no solo depende de los resultados lógicos de las operaciones, sino también del tiempo en que estos resultados son producidos. Ada es un lenguaje de programación que ofrece características robustas para el desarrollo de sistemas en tiempo real, gracias a su soporte para concurrencia, sincronización y manejo de tiempo.

Objetivos

  • Comprender los conceptos básicos de los sistemas en tiempo real.
  • Aprender a utilizar las características de Ada para desarrollar aplicaciones en tiempo real.
  • Implementar tareas y mecanismos de sincronización en Ada.
  • Manejar temporizadores y eventos temporales.

Conceptos Clave

  1. Sistemas en Tiempo Real: Sistemas que deben responder a eventos dentro de un tiempo predefinido.
  2. Tareas: Unidades de ejecución concurrente en Ada.
  3. Objetos Protegidos: Mecanismos para la sincronización y comunicación entre tareas.
  4. Temporizadores: Herramientas para medir y controlar el tiempo en aplicaciones en tiempo real.

Tareas en Tiempo Real

En Ada, las tareas son la base de la programación concurrente y en tiempo real. Una tarea en Ada se define de la siguiente manera:

task type Real_Time_Task is
    entry Start;
end Real_Time_Task;

task body Real_Time_Task is
begin
    accept Start;
    -- Código de la tarea
end Real_Time_Task;

Ejemplo Práctico

Vamos a crear una tarea que se ejecuta periódicamente cada segundo.

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

procedure Periodic_Task is
    task type Task_Type is
        entry Start;
    end Task_Type;

    task body Task_Type is
        Next_Time : Time := Clock;
    begin
        accept Start;
        loop
            Put_Line("Task executed at " & Time'Image(Clock));
            Next_Time := Next_Time + Milliseconds(1000);
            delay until Next_Time;
        end loop;
    end Task_Type;

    T : Task_Type;
begin
    T.Start;
end Periodic_Task;

Explicación del Código

  1. Importación de Paquetes: Ada.Real_Time para manejar el tiempo y Ada.Text_IO para la salida de texto.
  2. Definición de la Tarea: Task_Type con una entrada Start.
  3. Cuerpo de la Tarea:
    • Next_Time se inicializa con el tiempo actual.
    • La tarea acepta la entrada Start y entra en un bucle infinito.
    • En cada iteración, imprime la hora actual y espera hasta el próximo segundo usando delay until.

Sincronización y Comunicación

Para sincronizar tareas y permitir la comunicación entre ellas, Ada proporciona objetos protegidos.

Ejemplo de Objeto Protegido

protected type Shared_Data is
    procedure Write(Value : Integer);
    function Read return Integer;
private
    Data : Integer := 0;
end Shared_Data;

protected body Shared_Data is
    procedure Write(Value : Integer) is
    begin
        Data := Value;
    end Write;

    function Read return Integer is
    begin
        return Data;
    end Read;
end Shared_Data;

Explicación del Código

  1. Definición del Objeto Protegido: Shared_Data con un procedimiento Write y una función Read.
  2. Cuerpo del Objeto Protegido:
    • Write actualiza el valor de Data.
    • Read devuelve el valor de Data.

Temporizadores y Eventos Temporales

Ada proporciona mecanismos para manejar temporizadores y eventos temporales, esenciales en sistemas en tiempo real.

Ejemplo de Temporizador

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

procedure Timer_Example is
    Next_Time : Time := Clock;
begin
    loop
        Next_Time := Next_Time + Milliseconds(500);
        delay until Next_Time;
        Put_Line("Half a second passed at " & Time'Image(Clock));
    end loop;
end Timer_Example;

Explicación del Código

  1. Inicialización del Temporizador: Next_Time se establece con el tiempo actual.
  2. Bucle Infinito:
    • Next_Time se incrementa en 500 milisegundos.
    • La ejecución se retrasa hasta Next_Time.
    • Se imprime un mensaje indicando que ha pasado medio segundo.

Ejercicio Práctico

Ejercicio

Crea un programa en Ada que tenga dos tareas. La primera tarea debe imprimir un mensaje cada segundo, y la segunda tarea debe imprimir un mensaje cada dos segundos. Usa objetos protegidos para sincronizar el acceso a una variable compartida que cuenta el número de mensajes impresos.

Solución

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

procedure Dual_Task is
    protected type Counter is
        procedure Increment;
        function Get_Value return Integer;
    private
        Count : Integer := 0;
    end Counter;

    protected body Counter is
        procedure Increment is
        begin
            Count := Count + 1;
        end Increment;

        function Get_Value return Integer is
        begin
            return Count;
        end Get_Value;
    end Counter;

    Shared_Counter : Counter;

    task type Task_One is
        entry Start;
    end Task_One;

    task body Task_One is
        Next_Time : Time := Clock;
    begin
        accept Start;
        loop
            Next_Time := Next_Time + Milliseconds(1000);
            delay until Next_Time;
            Shared_Counter.Increment;
            Put_Line("Task One executed at " & Time'Image(Clock) & " Count: " & Integer'Image(Shared_Counter.Get_Value));
        end loop;
    end Task_One;

    task type Task_Two is
        entry Start;
    end Task_Two;

    task body Task_Two is
        Next_Time : Time := Clock;
    begin
        accept Start;
        loop
            Next_Time := Next_Time + Milliseconds(2000);
            delay until Next_Time;
            Shared_Counter.Increment;
            Put_Line("Task Two executed at " & Time'Image(Clock) & " Count: " & Integer'Image(Shared_Counter.Get_Value));
        end loop;
    end Task_Two;

    T1 : Task_One;
    T2 : Task_Two;
begin
    T1.Start;
    T2.Start;
end Dual_Task;

Explicación del Código

  1. Definición del Objeto Protegido: Counter con un procedimiento Increment y una función Get_Value.
  2. Cuerpo del Objeto Protegido:
    • Increment incrementa el contador.
    • Get_Value devuelve el valor del contador.
  3. Definición de las Tareas: Task_One y Task_Two con una entrada Start.
  4. Cuerpo de las Tareas:
    • Ambas tareas aceptan la entrada Start y entran en un bucle infinito.
    • Task_One se ejecuta cada segundo y Task_Two cada dos segundos.
    • Ambas tareas incrementan el contador compartido y imprimen el valor actual del contador.

Conclusión

En esta sección, hemos explorado cómo Ada puede ser utilizada para desarrollar sistemas en tiempo real. Hemos aprendido a definir y manejar tareas, utilizar objetos protegidos para la sincronización y manejar temporizadores. Estos conceptos son fundamentales para construir aplicaciones robustas y eficientes en tiempo real. En la siguiente sección, profundizaremos en la sincronización y comunicación entre tareas en Ada.

© Copyright 2024. Todos los derechos reservados