Up: Examen de Programación Concurrente
Previous: Lonja Online [1 hora,
Subsecciones
Asumamos la siguiente especificación formal del recurso
GestorSubasta:
Se pide:
- 2
- Implementación en Ada 95 del sistema (procesos
Vendedor, Comprador y gestor) usando procesos
distribuidos y rendez-vous y/o paso de mensajes.
[4 puntos]
- 3
- Implementación mediante objetos protegidos (sólo el
código del tipo protegido).[3 puntos]
Observación: No será necesario tener en cuenta posibles
problemas de vivacidad provocados exclusivamente por la
implementación indeterminista en Ada 95 de las llamadas a entries o
ramas de una select.
Nota: el código correspondiente a las implementaciones se
encuentra en este directorio,
en lugar de estar contenido en la presente página.
La declaración del interfaz del tipo tarea que implementa el gestor
aparece debajo. En ella se ha elegido utilizar rendez-vous en
todas las operaciones, excepto en Oir_Valor. En esta última
se ha elegido el uso de canales explícitos para implementar la
dependencia entre la precondición de concurrencia y los parámeros de
entrada. Esta operación, por tanto, cambia los tipos de sus
parámetros con respecto a la especificación, y el proceso que simula
un cliente cambia la llamada correspondiente de forma acorde.
El cuerpo de la tarea traduce casi directamente la especificación
dada. La entrada correspondiente a Oir_Valor almacena todas
las peticiones que llegan en una cola. Dichas peticiones se atienden
en un bucle al final de la construcción select.
El código de la tarea comprador cambia ligeramente para aguardar la
respuesta a la llamada Oir_Valor, que señala cuándo el
precio requerido por el lote ha cambiado con respecto al anterior.
Algunos comentarios sobre vuestros ejercicios:
- Hay un número sorprendentemente alto de ejercicios que incluyen
el parámetro PrecioAnterior en la guarda de
OirValor.
- En algunos casos se detecta el problema con dicho parámetro pero
se ignora cómo resolverlo. Ejemplos de esto son: poner la guarda a
True y no hacer nada más (lo cual provoca la espera activa
que se trataba de evitar), ponerla a not Abierta (lo cual
provoca un interbloqueo inmediato), etc.
- La inmensa mayoría de las soluciones que aplican un esquema más
o menos similar al de la solución que proponemos sufren, sin
embargo, de algún problema en el código de desbloqueos. Algunos de
los más habituales son:
- Desencolar sin comprobar la CPRE. Esto provoca espera activa,
lo cual se trataba de evitar.
- Desencolar todos y contestar sólo a los que cumplen la
CPRE. Esto provoca el bloqueo de parte de los procesos
Comprador.
- Desencolar hasta que se encuentra un elemento de la cola que
no cumple la CPRE. Provoca que algunas peticiones aplazadas que se
podrían atender tengan que esperar innecesariamente a la siguiente
actualización. No es un fallo crítico en esta aplicación, pero
podría serlo en otro contexto.
- Finalmente, hay una serie de fallos que, sin afectar al esquema
fundamental de la solución, hemos de comentar por haber aparecido
más veces de lo deseado, como:
- Envíos o recepciones dentro del rendez-vous (provoca
interbloqueo).
- Mantener los parámetros de salida de OirValor tras
haberla reformado para usar paso de mensajes explícito.
Notas relativas a la solución:
- Es completamente incorrecto, al igual que en la pregunta de paso
mensajes, utilizar directamente variables que aparecen en la
cabecera de una entry o de un accept en la evaluación
de una guarda. Hacer un requeue tampoco soluciona esto de
por sí.
- Puede implementarse una solución similar a la utilizada para
paso de mensajes asignando un identificador diferente a cada
proceso, y almacenándolo en una estructura de datos tras cada
llamada a Oir_Valor junto con el precio oído. La llamada
a ésta operación se reencolaría internamente en una familia de
entradas. Los pares identificador/precio se revisarían tras cada
actualización del precio y tras cada puja y liberarían los procesos
que estuviesen esperando por ese cambio. Esta técnica (que es la
más general, al permitir controlar el rearranque al nivel de tareas
individuales), necesita una implementación relativamente laboriosa,
más propensa a errores y necesita cambiar el código de los procesos.
- Un rearranque uno a uno, en que se permite la existencia
de a lo sumo un proceso bloqueado en Oir_Val dentro
del objeto protegido y espacio para guardar los parámetros de esa
llamada, es válido. La justificación de la validez es que
Oir_Valor no realiza ninguna puja; existe un tiempo, no
determinado a priori entre el momento en que se escucha un
precio interesante y el momento en que se puja por él. Por ello,
aún en el caso de clientes que aceptan el mismo precio máximo,
existe la posibilidad de una inversión del orden de llegada a la
puja con respecto al orden de llegada a Oir_Valor. Lo
mismo puede aplicarse a clientes con ideas diferentes sobre
el valor máximo deseable. Muchos han intentado aplicar esta
solución de forma incorrecta, sin bloquear la entry más
externa. Esto hace que llamadas posteriores pueden sobreescribir el
estado que guarda argumentos de llamada de llamadas ya almacenados.
- Realizar la operación Oir_Valor con una familia de
entries tiene varios problemas:
- No sabemos realmente cómo está implementado
Tipo_Precio. Podría ser perfectamente un registro con la
parte entera y decimal de un precio.
- Incluso si el tipo es un tipo simple, podría no ser escalar (por
ejemplo, un Float).
- Aún en el caso de un escalar, su rango podría ser tan amplio que
no llevase a una eficiencia excesivamente baja (o incluso a errores
en tiempo de ejecución).
Los procesos Cliente y Vendedor no cambian, y las
cabeceras de los procedimientos son las mismas que en la
especificación. Se incluyen a continuación la declaración de
variables privadas del tipo protegido y el código del mismo.
Por completitud incluímos a continuación la parte relevante de una
implementación con familias de entries, suponiendo que es
posible utilizarla con el tipo de los precios del pescado:
Up: Examen de Programación Concurrente
Previous: Lonja Online [1 hora,
Manuel Carro
2002-02-22