Programación Concurrente Prácticas 1, 2 y 3 - Profe Saul
Programación Concurrente Prácticas 1, 2 y 3 - Profe Saul
Programación Concurrente Prácticas 1, 2 y 3 - Profe Saul
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Programación <strong>Concurrente</strong><br />
Prácticas 1, 2 y 3<br />
Dpto. LSIIS — Unidad de Programación Convocatoria de Febrero — curso 2006/2007<br />
Normas<br />
La fecha límite de entrega de la práctica 1 es el 11 de diciembre de 2006 a las 21:00.<br />
La fecha límite de entrega de la práctica 2 es el 8 de enero de 2007 a las 21:00.<br />
La fecha límite de entrega de la práctica 3 es el 22 de enero de 2007 a las 21:00.<br />
Deberá mencionarse explícitamente el uso de recursos (código, algoritmos específicos, esquemas<br />
de implementación, etc.) que no hayan sido desarrollados por el alumno o proporcionados<br />
como parte de asignaturas de la carrera. La falta de esta mención podrá impedir<br />
aprobar las prácticas.<br />
Os recordamos que todas las prácticas entregadas pasan por un proceso automático de detección<br />
de copias. Los involucrados en la copia de una práctica corren el riesgo de suspenderlas<br />
suspenderlas para el año académico en curso, independientemente de la calidad o<br />
adecuación del código.<br />
1. Pastas de té<br />
Una fábrica de pastas de té tiene tres hornos que producen pastas de diferentes pesos. Procedentes<br />
de los hornos, las pastas se van situando en una cinta transportadora común.<br />
Las pastas tienen que ser empaquetadas en cajas. Para ello, uno o varios robots empaquetadores<br />
toman pastas de la cinta y las introducen en la caja tal y como muestra la siguiente figura:<br />
Cada caja puede contener un número diferente de pastas siempre y cuando no se sobrepase<br />
un peso límite. Por este motivo, antes de incluir una pasta en la caja, cada empaquetador debe<br />
asegurarse de que con su inclusión no se sobrepasa el peso máximo. Si no se sobrepasa el peso se
2 Programación <strong>Concurrente</strong><br />
incluye la pasta en la caja; en otro caso, un operario debe retirar la caja que se estaba llenando y<br />
sustituirla por otra vacía.<br />
El objetivo consiste en llenar cada caja lo más posible. Esto puede ser conseguido por cualquiera<br />
de los robots empaquetadores que intentan depositar simultáneamente alguna pasta. Se nos<br />
asegura que no puede haber interferencias físicas entre brazos robot que intentan soltar pastas al<br />
mismo tiempo en la caja. Se pretende que haya la máxima concurrencia posible entre los brazos<br />
robot, es decir, que varios de ellos puedan retirar simultáneamente pastas de la cinta transportadora<br />
y, también simultáneamente, dejarlas en la caja. Hay que evitar, por otro lado, que se sobrepase<br />
el peso máximo admitido por la caja y que se intenten dejar pastas cuando no hay caja o cuando<br />
se está reponiendo.<br />
Para desarrollar el software de control se dispone de un paquete en Ada –ya programado–<br />
que proporciona, entre otros, los siguientes procedimientos de acceso a los robots y dispositivos<br />
mecánicos (se ignoran los hornos y la cinta; no es asunto del software de control):<br />
with Basicos;<br />
use Basicos;<br />
package Cadena is<br />
---------------------------------------------------------------------<br />
N_EMPAQUETADORES : constant Positive := 10;<br />
---------------------------------------------------------------------<br />
-- PESO_MAXIMO : constant Peso;<br />
-- function "=" (A, B : Peso) return Boolean;<br />
-- function "
Curso 2006/2007 — Convocatoria de Febrero 3<br />
2. Diseño<br />
Tras el análisis del problema, se incluye un diseño propuesto: grafo de recursos y procesos,<br />
código de los procesos y especificación del recurso. Asumimos que el recurso está contenido en<br />
una variable Cont_Caja accesible por los procesos cuyo tipo es Control_Caja<br />
Tomar_Pasta<br />
(E,P)<br />
Reponer_Caja<br />
Caja<br />
Empaquetadores<br />
(E)<br />
Comunicar_Peso<br />
(Caja, P)<br />
Incrementar_Peso<br />
(Caja, P)<br />
Notificar_Reposicion<br />
Brazo<br />
Notificar_Pasta_En_Caja<br />
(Caja)<br />
Preparar_Reposicion<br />
Soltar_Pasta<br />
(E)<br />
Retirar_Caja<br />
Declaración de recurso:<br />
Cont_Caja : Control_Caja;<br />
Controlador de empaquetador:<br />
loop<br />
Tomar_Pasta (E, Peso_Pasta);<br />
Put_Line ("Emp." & Id_Empaquetador’Image (E) &<br />
" tomó pasta " & Tipo_Peso’Image (Peso_Pasta));<br />
Comunicar_Peso (Cont_Caja, Peso_Pasta);<br />
Incrementar_Peso (Cont_Caja, Peso_Pasta);<br />
Soltar_Pasta (E);<br />
Put_Line ("Emp." & Id_Empaquetador’Image (E) &<br />
" soltó pasta " & Tipo_Peso’Image (Peso_Pasta));<br />
Notificar_Pasta_En_Caja (Cont_Caja);<br />
end loop;<br />
Controlador de reponedor:<br />
loop<br />
Preparar_Reposicion (Cont_Caja);<br />
Put_Line ("+++ Retiramos caja");<br />
Retirar_Caja;<br />
Put_Line ("+++ Reponemos caja");<br />
Reponer_Caja;<br />
Notificar_Reposicion (Cont_Caja);<br />
end loop;<br />
Especificación del recurso:<br />
C-TADSOL Control Caja<br />
OPERACIONES<br />
ACCIÓN Preparar Reposicion: Control Caja[io]<br />
ACCIÓN Notificar Reposicion: Control Caja[io]<br />
ACCIÓN Comunicar Peso: Control Caja[io] × Peso[i]<br />
ACCIÓN Incrementar Peso: Control Caja[io] × Peso[i]<br />
ACCIÓN Notificar Pasta En Caja: Control Caja[io]<br />
SEMÁNTICA<br />
DOMINIO:
4 Programación <strong>Concurrente</strong><br />
TIPO: Control Caja= (peso: Peso × estado: Estado × accediendo: N)<br />
Estado = preparada | a reponer | reponiendo<br />
INICIAL(c): c = (0, preparada, 0)<br />
CPRE: c = ( , a reponer, 0)<br />
Preparar Reposicion(c)<br />
POST: c sal = (c ent .peso, reponiendo, 0)<br />
CPRE: verdad<br />
Notificar Reposicion(c)<br />
POST: c sal = (0, preparada, 0)<br />
CPRE: c.estado ≠ reponiendo<br />
Comunicar Peso(c, p)<br />
POST: c ent = (pin, , a) ∧ (pin + p > P ESO MAXIMO → c sal =<br />
(pin, a reponer, a)) ∧<br />
(pin + p ≤ P ESO MAXIMO → c sal = (pin, preparada, a))<br />
CPRE: c.peso + p ≤ P ESO MAXIMO ∧ c.estado ≠ reponiendo<br />
Incrementar Peso(c, p)<br />
POST: c ent = (pin, e, a) ∧ c sal = (pin + p, e, a + 1)<br />
CPRE: verdad<br />
Notificar Pasta En Caja(c)<br />
POST: c ent = (pin, e, a) ∧ c sal = (pin, e, a − 1)<br />
Notas informales sobre el funcionamiento del recurso<br />
La reposición pasa por tres fases: preparada (se pueden dejar pastas), a reponer (se debe reponer<br />
una caja, porque hay un robot que puede sobrepasar su capacidad) y reponiendo (se ha<br />
iniciado la secuencia de reposición). El estado a reponer no es irreversible, pues sólo señala que<br />
un brazo robot necesita una caja nueva, pero puede haber otro brazo que lleve una pasta de peso<br />
inferior al necesario para exceder el peso máximo de la caja. Si la señal de este segundo brazo<br />
llega a tiempo puede eliminar la petición de recambio y dejar una pasta que aún cabe en la caja.<br />
El estado reponiendo sí es irreversible, pues indica que el brazo reponedor ha recibido la necesidad<br />
de reposición e iniciará el proceso de cambio de caja.<br />
Para que haya un buen comportamiento en caso de varios robots, el peso de caja se guarda en<br />
el recurso, lo que garantiza su acceso atómico. La CPRE de Incrementar Peso asegura que:<br />
Ningún robot puede exceder el peso máximo (c.peso + p ≤ P ESO MAXIMO), pues se<br />
comprueba justo antes de intentar dejar la pasta y su POST incrementa (atómicamente)<br />
dicho peso antes de que este sea efectivo en la caja, con lo que el recurso contiene un avance<br />
del futuro de la caja y las decisiones tomadas según este valor son seguras.<br />
Ningún robot dejará una pasta mientras se está reponiendo la caja (c.estado ≠ reponiendo).<br />
Pero un robot cuya pasta no causa exceso de peso puede dejar la mercancía aunque haya<br />
otro robot bloqueado por su pasta mientras no se haya iniciado la secuencia de reposición.<br />
En este último caso, el robot que ha adelantado a los demás elimina la señal de reposición.<br />
Será este mismo (u otro, si hay más no bloqueados) el que la reactive, si es necesario, en el<br />
momento en que, tras dejar su pasta, adquiera otra del horno e intente depositarla en la caja. Esto<br />
intenta maximizar el peso final de la caja. De no hacerlo así, una solución extrema, correcta, pero<br />
evidentemente indeseable, es poner siempre una sola pasta y reponer la caja.
Curso 2006/2007 — Convocatoria de Febrero 5<br />
Una solucion que maximiza el peso en lo posible es esperar a todos los robots en una barrera,<br />
calcular qué combinación de pastas de entre las disponibles daría un mejor resultado, elegir la<br />
mejor de las pastas, depositar sólo esa pasta repetir el ciclo. Sin embargo esta solución tiene una<br />
concurrencia muy baja, ya que tiende a que en cada momento sólo un robot acceda a la caja y al<br />
mostrador.<br />
El conteo de número de brazos robot accediendo a la caja es necesario para implementar una<br />
exclusión parcial (como en los problemas de Lectores y Escritores) que impida que se inicie una<br />
reposición de la caja mientras un brazo robot accede a la misma. Ello podría suceder si mientras<br />
se deposita (físicamente) una pasta, otro robot excede el peso máximo y pide un cambio de caja<br />
que se inicia mientras el anterior está aún dejando la pasta. Por otra parte, se permite que varios<br />
brazos robots dejen simultáneamente pastas en la caja.<br />
3. Prácticas<br />
3.1. Primera práctica<br />
La entrega de la primera práctica constará de una implementación del recurso en Ada 95 usando<br />
objetos protegidos, basada en la especificación dada en el enunciado. La implementación a realizar<br />
debe estar contenida en un fichero llamado cajas de pastas.adb (ver el apartado 4).<br />
3.2. Segunda práctica<br />
La entrega de la segunda práctica constará de una implementación del recurso compartido en Ada<br />
95 mediante rendez-vous y/o paso de mensajes y basada en la especificación entregada en el enunciado.<br />
La implementación deberá estar contenida en un fichero llamado cajas de pastas.adb<br />
(ver el apartado 4).<br />
3.3. Tercera práctica<br />
Supongamos una variación del problema original en la que los robots empaquetadores no<br />
registran el peso de las pastas, sino que la plataforma en que está la caja tiene una balanza y en el<br />
paquete Cadena se dispone de una operación<br />
Peso_Balanza(P: out Peso)<br />
que es no bloqueante y de ejecución prácticamente inmediata.<br />
La entrega de la tercera práctica constará de una memoria en papel con un nuevo diseño que<br />
debe cumplir en lo posible los mismos requisitos que se tenían para el problema inicial. Puede<br />
modificarse todo lo que sea necesario, tanto en el diseño del recurso como en el código de las<br />
tareas. Debe entregarse el grafo de procesos y recursos (si ha variado), la especificación formal<br />
del recurso necesario para la sincronización de los procesos y el código de los procesos en función<br />
de la interfaz del recurso especificado.
6 Programación <strong>Concurrente</strong><br />
4. Información general<br />
El texto de estas prácticas se encuentra en<br />
http://lml.ls.fi.upm.es/pc/practicas/<br />
La entrega del código se realizará vía WWW en la dirección<br />
http://lml.ls.fi.upm.es/entrega/<br />
Las memorias pedidas (en la práctica 3) se entregarán en papel al profesor del grupo en el que<br />
se esté matriculado (se habilitará un buzón a la entrada de la unidad para ello). El código que<br />
entreguéis (para objetos protegidos o para paso de mensajes) no debe realizar ninguna operación<br />
de entrada / salida.<br />
Para facilitar la realización de la práctica se suministran varias unidades completas de compilación,<br />
de las que destacamos:<br />
fabrica: programa principal que arranca todas las demás tareas junto con el recurso compartido.<br />
cadena: simulación de las operaciones de una cadena como la descrita en el enunciado.<br />
Estas unidades están disponibles en http://lml.ls.fi.upm.es/pc/practicas/codigo.<br />
En la misma dirección se puede encontrar el interfaz (cajas_de_pastas.ads) del paquete con<br />
el tipo que representa el recurso compartido y un esqueleto de código (cajas_de_pastas.adb)<br />
que debéis completar (y posteriormente entregar) con la implementación del recurso compartido<br />
mediante objetos protegidos y mediante paso de mensajes.<br />
El código que entreguéis debe poder compilarse y ejecutar sin errores junto con el resto de<br />
los paquetes entregados sin modificar estos últimos, aunque los cambiéis y ajustéis para hacer<br />
pruebas durante el desarrollo. Podéis utilizar las librerías auxiliares que están disponibles en<br />
http://lml.ls.fi.upm.es/pc/lib/. Si os veis en la necesidad de usar algún otro paquete<br />
adicional que no venga con GNAT y que no os estemos proporcionando, hacédnoslo saber con<br />
antelación suficiente para evaluar la petición.<br />
El programa de recepción de prácticas podrá rechazar entregas que:<br />
Tengan errores de compilación.<br />
Utilicen otras librerías o paquetes aparte de los estándar de Ada y los que se han mencionado<br />
anteriormente.<br />
No estén suficientemente comentadas. Alrededor de un tercio de las líneas deben ser comentarios<br />
significativos. No se tomarán en consideración para su evaluación prácticas que tengan<br />
comentarios ficticios con el único propósito de rellenar espacio.<br />
Estén escritas con un estilo incorrecto: los programas se compilarán con el compilador GNAT<br />
y las opciones -gnaty -gnata. Recomendamos, por tanto, usar estas opciones para desarrollar<br />
las prácticas.<br />
No superen unas pruebas mínimas de ejecución.