Programación en Ada/Tareas/Selección de citas

← Tareas/Aceptación de citas Selección de citas Tareas/Llamadas a punto de entrada complejas →


Selección de citas (select)

editar

Uno de los usos de la sentencia select es permitir a una tarea seleccionar entre varias posibles citas; en este caso, se permite su uso únicamente dentro del cuerpo de una tarea. Su sintaxis es la siguiente:

seleccción_aceptación_cita ::=
  select
    [ when condición => ]
      ( acceptación_cita | ( delay [ until ] expresión )
      [ secuencia_de_sentencias ] )
      | ( terminate ; ) )
  { or
    [ when condición => ]
      ( acceptación_cita | ( delay [ until ] expresión )
      [ secuencia_de_sentencias ] )
      | ( terminate ; ) ) }
  [ else
    sequencia_sentencias ]
  end select ;

Esta alternativa de sentencia select permite una combinación de espera y selección entre varias aceptaciones de puntos de entrada a la tarea alternativas. Además, la selección puede depender de condiciones asociadas a cada alternativa.

La sentencia delay sirve para indicar que, si en un determinado intervalo de tiempo no se produce ninguna llamada que corresponda con las selecciones anteriores, se ejecuten las sentencias posteriores.

La sentencia terminate se elige en la sentencia select si la unidad de la que la tarea depende ha llegado al final y todas las tareas hermanas y dependientes han terminado. Es una terminación controlada. Esta alternativa no puede aparecer si hay una alternativa delay o else.

Por ejemplo:

task Servidor is
  entry Trabajar;
  entry Cerrar;
end;
task body Servidor is
begin
  loop
    select
      accept Trabajar do  -- Se acepta la llamada a trabajar.
        Trabajando := True;  -- Variable global.
      end;
      Trabajo_servidor;  -- Trabaja.
    or
      accept Cerrar;  -- Se cierra el servidor.
      exit;
    or
      delay (60.0);  -- ¿Se han olvidado del servidor?
      Put ("Estoy esperando trabajar.");
-- Otra opción en vez de delay:
-- or
--      --Terminación normal cuando se destruya el objeto tarea.
-- terminate;
    end select;
  end loop;
end Servidor;

Como otro ejemplo, para garantizar la exclusión mutua a una variable (acceso seguro a memoria compartida), se podría implementar con tareas de la siguiente manera:

task Variable_protegida is
  entry Leer (Elem: out TElemento);
  entry Escribir (Elem: TElemento);
end;
task body Variable_protegida is
  ElemLocal: TElemento;
begin
  accept Escribir (Elem: TElemento) do
    ElemLocal := Elem;
  end Escribir;
  loop
    select
      accept Escribir (Elem: TElemento) do
        ElemLocal := Elem;
      end Escribir;
    or
      accept Leer (Elem: out TElemento) do
        Elem := ElemLocal;
      end Leer;
    end select;
  end loop;
end Variable_protegida;

La primera sentencia de la tarea es un accept de Escribir, con lo que se asegura que la primera llamada le de un valor a la variable local. En el supuesto de que se realizara una llamada a Leer, ésta quedaría encolada hasta que se produjera la aceptación de Escribir. Después, la tarea entra en el bucle infinito que contiene una sentencia select. Es ahí donde se acepta tanto llamadas a Escribir como a Leer de la siguiente manera:

Si no se llama ni a Leer ni a Escribir, entonces la tarea se queda suspendida hasta que se llame a algún punto de entrada, en ese momento se ejecutará la sentencia accept correspondiente.

Si hay una o más llamadas en la cola de Leer, pero no hay llamadas en la de Escribir, se acepta la primera llamada a Leer, y viceversa.

Si hay llamadas tanto en la cola de Leer como en la de Escribir, se hace una elección arbitraria.

Es una tarea que sirve a dos colas de clientes que esperan servicios diferentes. Sin embargo, se impide el acceso múltiple a la variable local.

Manual de referencia de Ada

editar