Universidad Politécnica de Madrid Escuela Universitaria de Informática Departamento de Lenguajes, Proyectos y Sistemas Informáticos Asignatura PROGRAMACIÓN II EXAMEN DE LA CONVOCATORIA DE JULIO Plan: 92 / Curso: 2013-2014 Madrid a 4 de Julio de 2014 APELLIDOS: .................................. NOMBRE: ................................................. Nº DE MATRÍCULA: ........ DNI:................. GRUPO: ......................................... CALIFICACIONES TEORÍA PROB_1 PROB_2 TOTAL CUESTIONES TEÓRICAS Valoración: 3 puntos. Pregunta correcta:....................................0'2 puntos. Pregunta no contestada o incorrecta: .... -0'15 puntos I. PROGRAMACIÓN CONCURRENTE. 1. Dibuje el diagrama de estados de un proceso Preparado Ejecución Bloqueado 2. ¿Cómo definiría una acción atómica de grano fino? Aquélla que se implanta directamente por el Hardware en el que se ejecuta el programa concurrente Página 1 de 14 Programación II Julio 2014 3. En un semáforo cuyo contador es estrictamente positivo, ¿Puede haber algún proceso bloqueado? Justifique su respuesta NO. Cuando un proceso hace WAIT sobre un semáforo, si el contador es >0, éste se decrementa en 1 y prosigue su ejecución. Por el contrario un proceso que hace un SIGNAL sobre el semáforo, si hay procesos bloqueados, libera a uno y no incrementa el contador, manteniéndose a cero. 4. Describa la semántica utilizada por PASCAL_FC cuando un proceso desde el monitor A, invoca a un procedimiento de un monitor B y dentro de B ejecuta una operación DELAY. Mantiene la exclusión mutua sobre el monitor A y libera la exclusión mutua sobre el monitor B. 5. Ponga un ejemplo de problema en el que el acceso a las variables compartidas se haga de forma combinada, unas veces concurrente y otras con acceso exclusivo. El problema de los Lectores/Escritores II. PROGRAMACIÓN ORIENTADA A OBJETOS. 6. Defina la sobrecarga de métodos y cuáles son sus restricciones Definición de distintos métodos con el mismo nombre en la misma clase o en clases diferentes. En clases distintas no hay restricciones. En la misma clase ha de variar en el número de parámetros, o teniendo el mismo número de parámetros en los tipos de los parámetros dos a dos respectivamente 7. ¿Cuándo se ejecuta el método constructor de una clase?. Cuando se crea un objeto de esa clase (estática o dinámicamente) Página 2 de 14 Programación II Julio 2014 8. ¿Tiene sentido en la implantación de una clase cA, escribir el código SELF.MetodoA, cuando MetodoA es un método diferido de la clase cA? Razone su respuesta. SI porque el método puede estar redefinido en una clase derivada, y cuando el objeto de la clase derivada ejecute dicho código, SELF se referirá al objeto de la clase derivada y se ejecutará el método A tal como esté definido en esa clase. 9. ¿Cuáles son las características de la relación de asociación entre clases? Temporalidad: duradera, más que uso menos que composición. Versatilidad: limitada, menos que el uso más que la composición. Visibilidad: pública. 10. Atendiendo al gráfico de la figura, codifique en PIIPOO los atributos y constructores de las clases necesarios para la implantación de las mismas. CLASS INTERFACE cA; PUBLIC METHODS CONSTRUCTOR cA; END CLASS INTERFACE cA; cA composición composición cB cC Asociación CLASS INTERFACE cB; PUBLIC METHODS CONSTRUCTOR cB (pC: ^cC); END CLASS INTERFACE cB; CLASS IMPLEMENTATION cA; ATTRIBUTES mpC:^cC; mpB: ^cB; METHODS DEFINITION CONSTRUCTOR cA; BEGIN NEW (mpC, cC); NEW (mpB, cB(mpC) END; END CLASS IMPLEMENTATION cA; CLASS IMPLEMENTATION cB; ATTRIBUTES mpC:^cC; METHODS DEFINITION CONSTRUCTOR cB (pC: ^cC); BEGIN mpC:=pC; END; END CLASS IMPLEMENTATION cB; Página 3 de 14 Programación II III. Julio 2014 PROGRAMACIÓN FUNCIONAL. 11. Describa las funciones y operadores polimórficos que proporciona el lenguaje CAML, y defina sus tipos = y <>: fst: snd: :: ‘a * ‘a -> bool ‘a * ‘b -> ‘a ‘a * ‘b -> ‘b ‘a * ‘a list -> ‘a list if then else: hd: tl: bool* ‘a * ‘a -> ‘a ‘a list -> ‘a ‘a list -> ‘a list 12. ¿En qué consiste la evaluación perezosa de una expresión? La evaluación de una subexpresión depende de la necesidad de su evaluación durante la ejecución del programa. 13. Defina la transparencia referencial El valor de una expresión compuesta depende únicamente de sus componentes y de nada más. (no de la historia del programa en ejecución o de otros componentes que no estén inmersos en la expresión). 14. ¿Son válidos los siguientes patrones? Justifique su respuestas para aquellos patrones considerados inválidos. a. _:: x :: [y] :: [ [( _,a,`b`)] ] b. _ :: x :: (a,b) :: [(c,d,e)] c. (x<0,y) d. [snd(x,2);y] a. SI b. NO, porque los elementos de la lista deben ser del mismo tipo, y (a,b) es una tupla de 2 elementos y (c,d,e) es una tupla de 3 elementos. c. NO, no se puede poner una expresión condicional (x<0) en un patrón. d. NO, no se puede poner una expresión (snd(x,2)) en un patrón. 15. ¿Cuáles de los siguientes tipos son válidos?. Justifique su respuesta para aquellos tipos considerados inválidos. a. char*int -> char list b. [float] * int -> float c. _ * _ -> bool d. int * float -> true a. Válido b. Inválido: el primer elemento de la tupla quiere representar una lista de float, y el tipo es float list c. Inválido: un comodín _ NO puede formar parte de un tipo d. Inválido: la constante lógica true NO puede formar parte de un tipo Página 4 de 14 Programación II Julio 2014 Universidad Politécnica de Madrid Escuela Universitaria de Informática Departamento de Lenguajes, Proyectos y Sistemas Informáticos Asignatura PROGRAMACIÓN II ENUNCIADOS DE LOS PROBLEMAS DEL EXAMEN DE LA CONVOCATORIA DE JULIO Plan: 92 / Curso: 2013-2014 Madrid a 4 de Julio de 2014 Fechas de Publicación de Notas y de Revisión de Exámenes Publicación de Notas: Lunes 7 de Julio de 2014 Revisión de Examen y Prácticas: Viernes 11 de Julio de 2014 en horario que será publicado en el tablón de la Asignatura a la publicación de las notas Puede consultar sus notas en: www.lpsi.eui.upm.es/webprog2/Notas.htm PROBLEMA 1: PROGRAMACIÓN CONCURRENTE Puntuación: 2'5 puntos Una fábrica de un cierto producto está formada por NumMaquinas máquinas que producen NumTiposPiezas tipos de piezas, y por NumRobots robots de montaje que se encargan de ensamblar las piezas en el producto final. Los tipos de piezas se identifican mediante un valor entero comprendido entre 1 y NumTiposPiezas. Cada máquina está controlada por un proceso que tiene la siguiente estructura de operaciones ya implantadas en el sistema de control de la fábrica y que, por tanto, no pueden ser modificadas: PROCESS TYPE TMaquina (IdMaquina: INTEGER; TipoPieza : INTEGER); BEGIN REPEAT FabricarPieza(IdMaquina, TipoPieza); AlmacenarPieza(IdMaquina, TipoPieza) FOREVER END; Las máquinas fabrican repetidamente una pieza del mismo tipo. Una vez fabricada la pieza, se deposita en un almacén de piezas común para todas las máquinas. El almacén de piezas puede albergar un máximo de MaxPiezas piezas de cada tipo. Por su parte, cada robot de montaje se controla mediante un proceso en el que se ejecutan las siguientes operaciones inalterables ya definidas en el sistema de control de la fábrica: PROCESS TYPE TRobot (IdRobot : INTEGER); VAR TipoPieza : INTEGER; BEGIN REPEAT FOR TipoPieza := 1 TO NumTiposPiezas DO BEGIN RecogerPieza(IdRobot, TipoPieza); MontarPieza(IdRobot, TipoPieza) END FOREVER END; Página 5 de 14 Programación II Julio 2014 Los robots montan repetidamente productos, para lo cual montan las piezas en el producto en un orden determinado. Para montar cada pieza, primero se realiza una operación de recogida de la pieza del almacén de piezas, y después se monta la pieza en el producto. Se pide añadir a los procesos de control de las máquinas y los robots todo el código necesario para garantizar que se cumplan los siguientes requisitos: - Las máquinas pueden fabricar piezas y los robots pueden montar piezas en el producto sin sufrir ninguna interferencia por parte del resto de procesos. - Las máquinas no pueden almacenar una pieza de un cierto tipo si el almacén se encuentra lleno de piezas de ese tipo. - Los robots no pueden recoger del almacén una pieza de un cierto tipo si no hay ninguna disponible de ese tipo. - Cualquier número de máquinas puede almacenar concurrentemente piezas de distinto tipo en el almacén de piezas. Sin embargo, dos máquinas nunca pueden almacenar simultáneamente piezas del mismo tipo. - Los robots de montaje siempre deben acceder al almacén de piezas bajo exclusión mutua entre sí. - Una máquina puede almacenar una pieza y un robot puede recoger otra de tipo distinto concurrentemente. Si las piezas son del mismo tipo, el almacenamiento y la recogida debe hacerse bajo exclusión mutua. - En ausencia de competencia, ni las máquinas ni los robots deben esperar para acceder al almacén de piezas. Para cumplir los anteriores requisitos, los ingenieros de la fábrica han decidido seguir la siguiente política: - Una máquina sólo puede almacenar una pieza de un cierto tipo si el almacén puede albergar piezas de ese tipo, no hay ninguna otra máquina almacenando una pieza de ese tipo y no hay ningún robot recogiendo una pieza de ese tipo. En caso contrario, la máquina debe esperar para poder almacenar la pieza. - Un robot sólo puede recoger una pieza de un cierto tipo si hay piezas de ese tipo en el almacén, no hay ninguna máquina almacenando una pieza de ese tipo y no hay ningún robot recogiendo una pieza de cualquier tipo. En otro caso, el robot debe esperar para poder recoger la pieza. - Cuando una máquina termina de almacenar una pieza de un cierto tipo, primero comprueba si algún robot espera a recoger una pieza de ese tipo y puede recogerla, en cuyo caso lo libera. Si no hubiera tal robot, comprueba si alguna otra máquina espera a almacenar una pieza de ese tipo y puede almacenarla, en cuyo caso la libera. - Cuando un robot termina de recoger una pieza de un cierto tipo, primero busca algún otro robot que espere a recoger una pieza de cualquier tipo y pueda recogerla, en cuyo caso lo libera. Esta búsqueda se debe realizar de menor a mayor tipo de pieza. Además, después comprueba si alguna máquina espera a almacenar una pieza del mismo tipo que la pieza que se ha terminado de recoger y, si puede almacenarla, también la libera. Página 6 de 14 Programación II Julio 2014 (* ************************************************************************ *) MONITOR Almacen; EXPORT InicioAlmacenar, FinAlmacenar, InicioRecoger, FinRecoger; VAR NumPiezas : ARRAY [1..NumTiposPiezas] OF INTEGER; Almacenando : ARRAY [1..NumTiposPiezas] OF BOOLEAN; Recogiendo : BOOLEAN; TipoPiezaRecogida : INTEGER; ColaAlmacenar, ColaRecoger : ARRAY [1..NumTiposPiezas] OF CONDITION; i : INTEGER; (* ------------------------------------------------------------------------ *) FUNCTION SePuedeAlmacenar (TipoPieza : INTEGER) : BOOLEAN; BEGIN SePuedeAlmacenar := (NumPiezas[TipoPieza] < MaxPiezas) AND NOT Almacenando[TipoPieza] AND NOT (Recogiendo AND (TipoPieza = TipoPiezaRecogida)) END; (* ------------------------------------------------------------------------ *) FUNCTION SePuedeRecoger (TipoPieza : INTEGER) : BOOLEAN; BEGIN SePuedeRecoger := (NumPiezas[TipoPieza] > 0) AND NOT Almacenando[TipoPieza] AND NOT Recogiendo END; (* ------------------------------------------------------------------------ *) PROCEDURE InicioAlmacenar (TipoPieza : INTEGER); BEGIN (* Esperar a poder almacenar *) IF NOT SePuedeAlmacenar(TipoPieza) THEN DELAY(ColaAlmacenar[TipoPieza]); (* Comenzar a almacenar *) Almacenando[TipoPieza] := TRUE END; (* ------------------------------------------------------------------------ *) PROCEDURE FinAlmacenar (TipoPieza : INTEGER); BEGIN (* Terminar de almacenar *) Almacenando[TipoPieza] := FALSE; NumPiezas[TipoPieza] := NumPiezas[TipoPieza] + 1; (* Comprobar si un robot puede recoger una pieza del mismo tipo *) IF NOT EMPTY(ColaRecoger[TipoPieza]) AND SePuedeRecoger(TipoPieza) THEN RESUME(ColaRecoger[TipoPieza]) (* Comprobar si otra maquina puede almacenar una pieza del mismo tipo *) ELSE IF NOT EMPTY(ColaAlmacenar[TipoPieza]) AND SePuedeAlmacenar(TipoPieza) THEN RESUME(ColaAlmacenar[TipoPieza]) END; Página 7 de 14 Programación II Julio 2014 (* ------------------------------------------------------------------------ *) PROCEDURE InicioRecoger (TipoPieza : INTEGER); BEGIN (* Esperar a poder recoger *) IF NOT SePuedeRecoger(TipoPieza) THEN DELAY(ColaRecoger[TipoPieza]); (* Comenzar a recoger *) Recogiendo := TRUE; TipoPiezaRecogida := TipoPieza END; (* ------------------------------------------------------------------------ *) PROCEDURE FinRecoger; VAR TipoPieza, i : INTEGER; BEGIN (* Terminar de recoger *) Recogiendo := FALSE; NumPiezas[TipoPiezaRecogida] := NumPiezas[TipoPiezaRecogida] - 1; (* Guardar el tipo de la pieza recogida por este robot *) TipoPieza := TipoPiezaRecogida; (* Buscar otro robot que pueda recoger una pieza de cualquier tipo *) i := 1; WHILE (i < NumTiposPiezas) AND (EMPTY(ColaRecoger[i]) OR NOT SePuedeRecoger(i)) DO i := i + 1; IF NOT EMPTY(ColaRecoger[i]) AND SePuedeRecoger(i) THEN RESUME(ColaRecoger[i]); (* (* (* IF Comprobar si una maquina puede almacenar una pieza del mismo tipo *) que la pieza recogida por este robot, y de distinto tipo que la *) pieza del robot liberado (si lo hubiera) *) NOT EMPTY(ColaAlmacenar[TipoPieza]) AND SePuedeAlmacenar(TipoPieza) THEN RESUME(ColaAlmacenar[TipoPieza]) END; (* ------------------------------------------------------------------------ *) BEGIN FOR i := 1 TO NumTiposPiezas DO BEGIN Almacenando[i] := FALSE; Recogiendo := FALSE; NumPiezas[i] := 0 END END; Página 8 de 14 Programación II Julio 2014 (* ************************************************************************ *) PROCESS TYPE TMaquina (IdMaquina: INTEGER; TipoPieza : INTEGER); BEGIN REPEAT (* Fabricar una pieza *) FabricarPieza(IdMaquina, TipoPieza); (* Almacenar la pieza *) Almacen.InicioAlmacenar(TipoPieza); AlmacenarPieza(IdMaquina, TipoPieza); Almacen.FinAlmacenar(TipoPieza) FOREVER END; (* ************************************************************************ *) PROCESS TYPE TRobot (IdRobot : INTEGER); VAR TipoPieza : INTEGER; IdMaquina : ARRAY [1..NumTiposPiezas] OF INTEGER; BEGIN REPEAT FOR TipoPieza := 1 TO NumTiposPiezas DO BEGIN (* Recoger una pieza *) Almacen.InicioRecoger(TipoPieza); RecogerPieza(IdRobot, TipoPieza); Almacen.FinRecoger; (* Montar la pieza *) MontarPieza(IdRobot, TipoPieza) END FOREVER END; Página 9 de 14 Programación II Julio 2014 PROBLEMA 2: PROGRAMACIÓN ORIENTADA A OBJETOS Puntuación: 2'5 puntos En una gran aplicación se precisa de una gestión exhaustiva de fechas. Atendiendo a los requisitos se ha observado que, en una gran parte de la aplicación, la operación crítica es calcular la diferencia del número de días entre dos fechas. Por este motivo se propone para la clase cFecha el atributo dias (de la clase INTEGER) que contempla el número de días de una fecha transcurridos desde el nacimiento de Cristo. De esta manera se facilita la codificación de dicha operación y se optimiza su ejecución mediante la resta de dos números enteros. Por otro lado, en otra gran parte de la aplicación, la operación crítica es la presentación por pantalla. Por este motivo se propone para la clase cFecha el atributo cadena (de la clase STRING) que contempla las secuencia de caracteres con el formato habitual (dia/mes/año). De esta manera se facilita la codificación de dicha operación y se optimiza su ejecución mediante la presentación de una cadena ya formateada. Por último, en algunos puntos de la aplicación, existe la necesidad de combinar la gestión de fechas con los diseños de atributos presentados anteriormente. El diseño final responde a una solución de compromiso mediante una jerarquía de herencia con dos especializaciones que respondan a ambas propuestas anteriores. cFecha cFechaEntero cFechaCadena CLASS INTERFACE cFecha; END CLASS INTERFACE cFecha; CLASS INTERFACE cFechaEntero; INHERITS FROM cFecha; END CLASS INTERFACE cFechaEntero; CLASS IMPLEMENTATION cFechaEntero; ATTRIBUTES dias : INTEGER; PRIVATE METHODS FUNCTION toFechaCadena : ^cFechaCadena; END CLASS IMPLEMENTATION cFechaEntero; Página 10 de 14 Programación II Julio 2014 CLASS INTERFACE cFechaCadena; INHERITS FROM cFecha; END CLASS INTERFACE cFechaCadena; CLASS IMPLEMENTATION cFechaCadena; ATTRIBUTES cadena : STRING PRIVATE METHODS FUNCTION toFechaEntero : ^cFechaEntero; END CLASS IMPLEMENTATION cFechaCadena; SE PIDE: Incorporar el todo código necesario a la jerarquía de clases anterior para que cualquier fecha responda a los siguientes métodos: PROCEDURE presentar; FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; NOTA: Los métodos privados anteriores (toFechaCadena y toFechaEntero) para la conversión de objetos de una clase hija a la otra y viceversa se encuentran disponibles sin necesidad de su implantación. SOLUCIÓN 1: CLASS INTERFACE cFecha; PUBLIC METHODS DEFERRED PROCEDURE presentar; DEFERRED FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; DEFERRED FUNCTION getDias : INTEGER; END CLASS INTERFACE cFecha; (***************************************************************************) CLASS INTERFACE cFechaEntero; INHERITS FROM cFecha; PUBLIC METHODS REDEFINED PROCEDURE presentar; REDEFINED FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; REDEFINED FUNCTION getDias : INTEGER; END CLASS INTERFACE cFechaEntero; (*-------------------------------------------------------------------------*) CLASS IMPLEMENTATION cFechaEntero; ATTRIBUTES dias : INTEGER; PRIVATE METHODS FUNCTION toFechaCadena : ^cFechaCadena; Página 11 de 14 Programación II METHODS DEFINITION Julio 2014 PROCEDURE presentar; BEGIN SELF.toFechaCadena^.presentar END; FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; BEGIN diferencia := dias – pFecha^.getDias END; FUNCTION getDias : INTEGER; BEGIN getDias := dias END; END CLASS IMPLEMENTATION cFechaEntero; (***************************************************************************) CLASS INTERFACE cFechaCadena; INHERITS FROM cFecha; PUBLIC METHODS REDEFINED PROCEDURE presentar; REDEFINED FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; REDEFINED FUNCTION getDias : INTEGER; END CLASS INTERFACE cFechaCadena; (*-------------------------------------------------------------------------*) Página 12 de 14 Programación II Julio 2014 CLASS IMPLEMENTATION cFechaCadena; ATTRIBUTES cadena : STRING; PRIVATE METHODS FUNCTION toFechaEntero : ^cFechaEntero; METHODS DEFINITION PROCEDURE presentar; BEGIN cadena.WRITELN END; FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; BEGIN diferencia := SELF.getDias – pFecha^.getDias END; FUNCTION getDias : INTEGER; BEGIN getDias := SELF.toFechaEntero^.getDias END; END CLASS IMPLEMENTATION cFechaCadena; SOLUCIÓN 2: CLASS INTERFACE cFecha; PUBLIC METHODS PROCEDURE presentar; FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; DEFERRED FUNCTION getDias : INTEGER; DEFERRED FUNCTION getCadena : STRING; END CLASS INTERFACE cFecha; (*-------------------------------------------------------------------------*) CLASS IMPLEMENTATION cFecha; METHODS DEFINITION PROCEDURE presentar; BEGIN SELF.getCadena.WRITELN END; FUNCTION diferencia (pFecha : POLYMORPHIC ^cFecha) : INTEGER; BEGIN diferencia := SELF.getDias – pFecha^.getDias END; END CLASS IMPLEMENTATION cFecha; (***************************************************************************) Página 13 de 14 Programación II Julio 2014 CLASS INTERFACE cFechaEntero; INHERITS FROM cFecha; PUBLIC METHODS REDEFINED FUNCTION getDias : INTEGER; REDEFINED FUNCTION getCadena : STRING; END CLASS INTERFACE cFechaEntero; (*-------------------------------------------------------------------------*) CLASS IMPLEMENTATION cFechaEntero; ATTRIBUTES dias : INTEGER; PRIVATE METHODS FUNCTION toFechaCadena : ^cFechaCadena; METHODS DEFINITION FUNCTION getDias : INTEGER; BEGIN getDias := dias END; FUNCTION getCadena : STRING; BEGIN getCadena := SELF.toFechaCadena^.getCadena END; END CLASS IMPLEMENTATION cFechaEntero; (***************************************************************************) CLASS INTERFACE cFechaCadena; INHERITS FROM cFecha; PUBLIC METHODS REDEFINED FUNCTION getDias : INTEGER; REDEFINED FUNCTION getCadena : STRING; END CLASS INTERFACE cFechaCadena; (*-------------------------------------------------------------------------*) CLASS IMPLEMENTATION cFechaCadena; ATTRIBUTES cadena : STRING; PRIVATE METHODS FUNCTION toFechaEntero : ^cFechaEntero; METHODS DEFINITION FUNCTION getDias : INTEGER; BEGIN getDias := SELF.toFechaEntero^.getDias END; FUNCTION getCadena : STRING; BEGIN getCadena := cadena END; END CLASS IMPLEMENTATION cFechaCadena; Página 14 de 14