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

← Tareas/Sincronización mediante citas Aceptación de citas Tareas/Selección de citas →


Aceptación de citas (accept)

editar

La forma de aceptar una cita y ejecutar las sentencias que se deseen es mediante la sentencia accept, dentro del cuerpo de la tarea que acepta la cita. Cada sentencia entry debe corresponderse con una sentencia accept.

La sintaxis de accept es:

acceptación_cita ::=
  accept identificador [ ( expresión ) ]
    [ ( especificación_parámetro { ; especificación parámetro } ) ] [ do
    secuencia_de_sentencias
  end [ identificador ] ] ;

Por ejemplo:

accept Entrada (N: Integer) do
  -- ... Secuencia de sentencias.
end Entrada;

Se deben repetir los parámetros formales declarados en el punto de entrada de la especificación de la tarea.

La diferencias fundamentales entre los puntos de entrada y los procedimientos son:

  • El código existente dentro en la sentencia accept es ejecutado por la tarea propietaria y no por la parte invocante, como en los procedimientos.
  • Además, hasta que la tarea no llegue a la ejecución de dicha sentencia accept, no puede ser invocado el punto de entrada. De igual manera, la parte invocante queda suspendida hasta que termine la ejecución de la sentencia accept. Éste es el fundamento de la cita.

La forma más simple de sincronizar una tarea que dependa de la terminación de otro código es por ejemplo:

task Simple is
  entry Continuar;
end Simple;
task body Simple is
begin
  -- ...
  accept Continuar;  -- Se queda bloqueado hasta que se cite.
  -- ...  
end Simple;

Como otro ejemplo, si se quiere implementar una tarea que realice un control de escritura y lectura sobre un buffer de un único elemento:

task Buffer1 is
  entry Escribir (Elem: TElemento);
  entry Leer (Elem: out TElemento);
end Buffer1;
task body Buffer1 is
  ElemLocal: TElemento;
begin
  loop
    accept Escribir (Elem: TElemento) do
      ElemLocal:= Elem;  -- Guarda el elemento.
    end Escribir;
    Ada.Text_IO.Put_Line("Elemento escrito, voy a intentar LEER!");
    accept Leer (Elem: out TElemento) do
      Elem := ElemLocal;  -- Devuelve el elemento.
    end Leer;
    Ada.Text_IO.Put_Line("Elemento leido, vuelvo a intentar ESCRIBIR");
  end loop;
end Buffer1;

Se aceptan llamadas Buffer1.Escribir(…) y Buffer1.Leer(…) de forma consecutiva, sin posibilidad de escribir o leer dos o más veces seguidas. Varias tareas diferentes pueden invocar a los puntos de entrada y, por tanto, pueden quedar encoladas. Cada punto de entrada tiene una cola de tareas que esperan llamar a dicho punto de entrada. El atributo Escribir'Count contiene el número de tareas que se encuentran encoladas a la espera de que se ejecute el punto de entrada Escribir, pero sólo se puede utilizar dentro de la tarea que contiene el punto de entrada. Con la ejecución de la sentencia accept se extraería la primera tarea de la cola (la primera que llegó).

Por tanto, el ejemplo anterior funciona de la siguiente manera: la tarea Buffer1 llega al accept de Escribir y se queda bloqueada allí hasta que otra tarea realice una llamada Buffer1.Escribir(…). En ese momento, la tarea Buffer1 ejecuta Escribir y llega al accept de Leer, donde se queda bloqueada hasta que otra tarea realice una llamada Buffer1.Leer(…). Se ejecuta Leer y la tarea Buffer1 vuelve al accept de Escribir, y así constantemente. Evidentemente, si hay tareas encoladas en los puntos de entrada de Escribir o de Leer, la tarea Buffer1 no se queda bloqueada, sino que atiende a la primera tarea llamante de la cola.


Se puede introducir código entre dos bloques de accept, tal y como se ve en el ejemplo anterior: cuando se acaba el primer bloque accept (Escribir) se ejecuta dicho código y después se entra en la cola de espera del segundo bloque accept (Leer).


Si hay definidos varios puntos de entrada simultáneamente, se puede aceptar uno de ellos, por ejemplo, como:

accept Aviso (3) (Elem: Telemento) do
  -- ...
end Aviso;

Manual de referencia de Ada

editar