Programación en Ada/Tareas/Aceptación de citas
Aceptación de citas (accept)
editarLa 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_sentenciasend
[ 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 sentenciaaccept
. É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
Simpleis
entry
Continuar;end
Simple;task
body
Simpleis
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
Buffer1is
entry
Escribir (Elem: TElemento);entry
Leer (Elem:out
TElemento);end
Buffer1;task
body
Buffer1is
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;