Programación en Ada/Tareas/Aceptació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;