Introducción

En Ada, los objetos protegidos son una característica avanzada que permite la sincronización y la comunicación segura entre tareas concurrentes. Los objetos protegidos proporcionan un mecanismo para garantizar que las operaciones críticas se realicen de manera atómica, evitando condiciones de carrera y otros problemas de concurrencia.

Conceptos Clave

  1. Objeto Protegido: Una estructura que encapsula datos y operaciones, garantizando que las operaciones se realicen de manera segura en un entorno concurrente.
  2. Operaciones Protegidas: Métodos definidos dentro de un objeto protegido que pueden ser llamados por tareas concurrentes.
  3. Entrada Protegida: Un tipo especial de operación protegida que puede ser bloqueada hasta que se cumpla una condición específica.
  4. Exclusión Mutua: Garantiza que solo una tarea puede ejecutar una operación protegida a la vez.

Definición de un Objeto Protegido

Un objeto protegido se define utilizando la palabra clave protected. Aquí hay un ejemplo básico:

protected type Shared_Counter is
   procedure Increment;
   function Value return Integer;
private
   Counter : Integer := 0;
end Shared_Counter;

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

   function Value return Integer is
   begin
      return Counter;
   end Value;
end Shared_Counter;

Explicación del Código

  • Declaración del Tipo Protegido: protected type Shared_Counter is define un tipo protegido llamado Shared_Counter.
  • Operaciones Protegidas: procedure Increment y function Value return Integer son las operaciones protegidas que pueden ser llamadas por tareas concurrentes.
  • Sección Privada: private define la sección donde se declaran los datos internos del objeto protegido. En este caso, Counter es una variable entera que se inicializa a 0.
  • Cuerpo del Objeto Protegido: protected body Shared_Counter is define la implementación de las operaciones protegidas.

Uso de Objetos Protegidos

Para utilizar un objeto protegido, primero se debe declarar una instancia del tipo protegido y luego llamar a sus operaciones:

declare
   My_Counter : Shared_Counter;
begin
   My_Counter.Increment;
   Put_Line("Counter Value: " & Integer'Image(My_Counter.Value));
end;

Explicación del Código

  • Declaración de la Instancia: My_Counter : Shared_Counter declara una instancia del tipo protegido Shared_Counter.
  • Llamada a Operaciones Protegidas: My_Counter.Increment incrementa el contador y My_Counter.Value obtiene el valor actual del contador.

Ejemplo Práctico

Vamos a crear un ejemplo más complejo donde varias tareas incrementan un contador protegido:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Main is
   protected type Shared_Counter is
      procedure Increment;
      function Value return Integer;
   private
      Counter : Integer := 0;
   end Shared_Counter;

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

      function Value return Integer is
      begin
         return Counter;
      end Value;
   end Shared_Counter;

   My_Counter : Shared_Counter;

   task type Worker is
   end Worker;

   task body Worker is
   begin
      for I in 1 .. 100 loop
         My_Counter.Increment;
      end loop;
   end Worker;

   Workers : array (1 .. 10) of Worker;
begin
   delay 1.0;  -- Esperar a que todas las tareas terminen
   Put_Line("Final Counter Value: " & Integer'Image(My_Counter.Value));
end Main;

Explicación del Código

  • Declaración del Tipo Protegido: Igual que antes, se define Shared_Counter con operaciones Increment y Value.
  • Declaración de la Instancia: My_Counter : Shared_Counter declara una instancia del tipo protegido.
  • Tarea Worker: Se define una tarea que incrementa el contador 100 veces.
  • Array de Tareas: Workers : array (1 .. 10) of Worker declara un array de 10 tareas Worker.
  • Sincronización: delay 1.0 espera un segundo para asegurarse de que todas las tareas hayan terminado antes de imprimir el valor final del contador.

Ejercicio Práctico

Ejercicio

Modifica el ejemplo anterior para que cada tarea Worker incremente el contador un número aleatorio de veces entre 1 y 100.

Solución

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Numerics.Float_Random;

procedure Main is
   protected type Shared_Counter is
      procedure Increment;
      function Value return Integer;
   private
      Counter : Integer := 0;
   end Shared_Counter;

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

      function Value return Integer is
      begin
         return Counter;
      end Value;
   end Shared_Counter;

   My_Counter : Shared_Counter;

   task type Worker is
   end Worker;

   task body Worker is
      package Random is new Ada.Numerics.Float_Random;
      Gen : Random.Generator;
      Random_Value : Float;
      Increment_Count : Integer;
   begin
      Random_Value := Random.Random(Gen);
      Increment_Count := Integer(Random_Value * 100.0) + 1;
      for I in 1 .. Increment_Count loop
         My_Counter.Increment;
      end loop;
   end Worker;

   Workers : array (1 .. 10) of Worker;
begin
   delay 1.0;  -- Esperar a que todas las tareas terminen
   Put_Line("Final Counter Value: " & Integer'Image(My_Counter.Value));
end Main;

Explicación del Código

  • Generación de Números Aleatorios: Se utiliza el paquete Ada.Numerics.Float_Random para generar un número aleatorio entre 0 y 1.
  • Cálculo del Número de Incrementos: Increment_Count := Integer(Random_Value * 100.0) + 1 convierte el valor aleatorio en un número entero entre 1 y 100.
  • Bucle de Incremento: for I in 1 .. Increment_Count loop incrementa el contador el número aleatorio de veces.

Conclusión

En esta sección, hemos aprendido sobre los objetos protegidos en Ada, cómo definirlos y utilizarlos para sincronizar tareas concurrentes. Los objetos protegidos son una herramienta poderosa para garantizar la seguridad y la integridad de los datos en aplicaciones concurrentes. En la próxima sección, exploraremos los sistemas en tiempo real y cómo Ada maneja la concurrencia en estos entornos.

© Copyright 2024. Todos los derechos reservados