En este módulo, exploraremos uno de los aspectos más poderosos y distintivos de Ada: su capacidad para manejar tareas y concurrencia. Ada fue diseñado con la concurrencia en mente, lo que lo hace especialmente adecuado para aplicaciones en tiempo real y sistemas embebidos.
Conceptos Clave
- Tareas en Ada: Las tareas son unidades de ejecución concurrente.
- Declaración de Tareas: Cómo declarar y definir tareas en Ada.
- Comunicación entre Tareas: Métodos para que las tareas se comuniquen entre sí.
- Sincronización: Mecanismos para sincronizar tareas y evitar condiciones de carrera.
Declaración de Tareas
En Ada, una tarea se declara de manera similar a un procedimiento, pero con la palabra clave task. Aquí hay un ejemplo básico:
task type Worker is
entry Start_Work;
end Worker;
task body Worker is
begin
accept Start_Work do
-- Código para iniciar el trabajo
end Start_Work;
-- Código de la tarea
end Worker;Explicación del Código
- task type Worker: Declara un tipo de tarea llamado
Worker. - entry Start_Work: Declara una entrada que puede ser llamada para iniciar el trabajo.
- task body Worker: Define el cuerpo de la tarea
Worker. - accept Start_Work: Bloquea la tarea hasta que
Start_Worksea llamado.
Creación y Ejecución de Tareas
Para crear y ejecutar una tarea, simplemente declaramos una instancia de la tarea y llamamos a su entrada:
Explicación del Código
- Task1 : Worker: Crea una instancia de la tarea
Worker. - Task1.Start_Work: Llama a la entrada
Start_Workpara iniciar la tarea.
Comunicación entre Tareas
Ada proporciona varias formas de comunicación entre tareas, incluyendo entradas y mensajes. Aquí hay un ejemplo de cómo dos tareas pueden comunicarse usando entradas:
task type Sender is
entry Send_Message(Msg : in String);
end Sender;
task body Sender is
begin
accept Send_Message(Msg : in String) do
-- Enviar mensaje
end Send_Message;
end Sender;
task type Receiver is
entry Receive_Message(Msg : out String);
end Receiver;
task body Receiver is
Msg : String(1..100);
begin
accept Receive_Message(Msg : out String) do
-- Recibir mensaje
end Receive_Message;
end Receiver;Explicación del Código
- Sender: Tarea que envía un mensaje.
- Receiver: Tarea que recibe un mensaje.
- accept Send_Message: Bloquea hasta que
Send_Messagesea llamado. - accept Receive_Message: Bloquea hasta que
Receive_Messagesea llamado.
Sincronización
La sincronización es crucial para evitar condiciones de carrera y asegurar que las tareas se ejecuten en el orden correcto. Ada proporciona varios mecanismos para la sincronización, incluyendo los objetos protegidos y las barreras de entrada.
Ejemplo de Sincronización con Objetos Protegidos
protected type Shared_Data is
procedure Write(Data : in Integer);
function Read return Integer;
private
Value : Integer := 0;
end Shared_Data;
protected body Shared_Data is
procedure Write(Data : in Integer) is
begin
Value := Data;
end Write;
function Read return Integer is
begin
return Value;
end Read;
end Shared_Data;
task type Writer is
end Writer;
task body Writer is
Shared : Shared_Data;
begin
Shared.Write(10);
end Writer;
task type Reader is
end Reader;
task body Reader is
Shared : Shared_Data;
Value : Integer;
begin
Value := Shared.Read;
end Reader;Explicación del Código
- protected type Shared_Data: Declara un tipo protegido que asegura el acceso exclusivo a los datos compartidos.
- procedure Write: Procedimiento para escribir datos.
- function Read: Función para leer datos.
- Writer: Tarea que escribe datos.
- Reader: Tarea que lee datos.
Ejercicio Práctico
Ejercicio
Crea un programa en Ada que tenga dos tareas: una tarea Producer que genere números enteros y los envíe a una tarea Consumer que los imprima en la consola.
Solución
task type Producer is
entry Produce(Number : in Integer);
end Producer;
task body Producer is
begin
for I in 1..10 loop
accept Produce(Number : in Integer) do
-- Producir número
end Produce;
end loop;
end Producer;
task type Consumer is
entry Consume(Number : in Integer);
end Consumer;
task body Consumer is
Number : Integer;
begin
for I in 1..10 loop
accept Consume(Number : in Integer) do
-- Consumir número
Put_Line("Consumed: " & Integer'Image(Number));
end Consume;
end loop;
end Consumer;
procedure Main is
Prod : Producer;
Cons : Consumer;
begin
for I in 1..10 loop
Prod.Produce(I);
Cons.Consume(I);
end loop;
end Main;Explicación del Código
- Producer: Tarea que produce números.
- Consumer: Tarea que consume números.
- Main: Procedimiento principal que coordina la producción y el consumo.
Conclusión
En esta sección, hemos aprendido sobre las tareas y la concurrencia en Ada. Hemos visto cómo declarar y definir tareas, cómo comunicarse entre ellas y cómo sincronizarlas. Estos conceptos son fundamentales para escribir programas concurrentes y en tiempo real en Ada. En el próximo módulo, exploraremos los objetos protegidos y otros mecanismos avanzados de concurrencia.
¡Sigue practicando y experimentando con tareas para dominar la concurrencia en Ada!
Curso de Programación en Ada
Módulo 1: Introducción a Ada
Módulo 2: Conceptos Básicos
- Variables y Tipos de Datos
- Operadores y Expresiones
- Estructuras de Control
- Bucles en Ada
- Subprogramas: Procedimientos y Funciones
Módulo 3: Tipos de Datos Avanzados
Módulo 4: Programación Modular
Módulo 5: Concurrencia y Programación en Tiempo Real
Módulo 6: Temas Avanzados
Módulo 7: Mejores Prácticas y Optimización
- Estilo de Código y Mejores Prácticas
- Depuración y Pruebas
- Optimización del Rendimiento
- Consideraciones de Seguridad
