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 FEBRERO Plan: 92 / Curso: 2006-2007 Madrid, a 6 de Febrero de 2007 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 UTILICE EL REVÉS DE LAS HOJAS DE PROBLEMAS COMO BORRADOR I. PROGRAMACIÓN CONCURRENTE 1. ¿Qué es un interbloqueo de procesos? Es un estado de un programa concurrente en el que un conjunto de procesos permanece esperando un suceso que sólo puede provocar un proceso del propio conjunto, con lo que todos los procesos esperan indefinidamente. El interbloqueo puede ser pasivo (deadlock) o activo (livelock). 2. Describa la semántica de las instrucciones WAIT y SIGNAL aplicadas sobre semáforos generales. WAIT(s) – Si el contador del semáforo s es igual a cero el proceso se bloquea en el semáforo s; si no, se decrementa en una unidad el contador del semáforo s y el proceso prosigue su ejecución. SIGNAL(s) – Si hay procesos bloqueados en el semáforo s se despierta a uno de ellos; si no, se incrementa en una unidad el contador del semáforo s. En ambos casos, el proceso prosigue su ejecución. Ambas instrucciones son, por definición, atómicas. Página 1 de 10 Programación II Febrero 2007 3. Dado el programa siguiente ¿podría darse el caso de que uno o ninguno de los dos procesos finalizase? Razone su respuesta. PROGRAM P; PROCESS TYPE tProceso (VAR Fin : BOOLEAN); VAR I : INTEGER; BEGIN I:=0; WHILE NOT Fin DO BEGIN I:=I+1; IF I=3 THEN Fin:=TRUE ELSE Fin:=FALSE END END; VAR Procesos : ARRAY [1..2] OF tProceso; Fin : BOOLEAN; BEGIN Fin:=FALSE; COBEGIN Procesos[1](Fin); Procesos[2](Fin); COEND END. Si es posible. Ambos procesos entran en el bucle con la variable global Fin a valor FALSE. Si el proceso 1 ejecuta su bucle 3 veces, pondrá su variable local i a valor 3 y la variable global Fin a valor TRUE. En ese momento el proceso 2 pone su variable local i a valor 1 y la variable global Fin a valor FALSE. Si ahora el proceso 1 consulta la variable Fin permanecerá en el bucle. Si cuando el proceso 2 ponga su variable local i valor 3 y la variable global Fin a valor TRUE, el proceso 1 pone su variable local a valor 4 y la variable global Fin a valor FALSE, ambos procesos permanecerán indefinidamente en el bucle. 4. ¿Puede haber procesos bloqueados en la cola urgente de un monitor de Pascal-FC si dicho monitor no tiene declarada ninguna variable de tipo condición? Razone su repuesta No. Los procesos se bloquean en la cola urgente de un monitor al hacer un RESUME sobre una variable CONDITION y liberar un proceso bloqueado en esa variable CONDITION. Si no hay ninguna variable CONDITION en el monitor, no es posible realizar ningún RESUME sobre ella. 5. ¿Qué sucede en PASCAL-FC con la exclusión mutua sobre dos monitores A y B cuando un proceso, desde el monitor A, invoca a un procedimiento del monitor B y ejecuta una operación DELAY en ese procedimiento? Que retiene la exclusión mutua sobre el monitor A, y libera la exclusión mutua sobre el monitor B. Página 2 de 10 Programación II Febrero 2007 II. PROGRAMACIÓN ORIENTADA A OBJETOS 6. Atendiendo al siguiente diagrama de clases, codifique en PIIPOO los atributos y métodos de las clases cA y cB necesarios para la implantación de sus relaciones. cA Composición Composición cB cC Asociación CLASS INTERFACE cA; PUBLIC METHODS CONSTRUCTOR cA; END CLASS INTERFACE cA; CLASS INTERFACE cB; PUBLIC METHODS CONSTRUCTOR cB (pC: ^cC); END CLASS INTERFACE cB; CLASS IMPLEMENTATION cA; ATTRIBUTES mpC: ^cC; mpB: ^cB; CLASS IMPLEMENTATION cB; ATTRIBUTES mpC: ^cC; METHODS DEFINITION CONSTRUCTOR cA; BEGIN NEW (mpC, cC); NEW (mpB, cB(mpC) END; END CLASS IMPLEMENTATION cA; METHODS DEFINITION CONSTRUCTOR cB (pC: ^cC); BEGIN mpC:=pC; END; END CLASS IMPLEMENTATION cB; 7. Dadas las vistas públicas de las siguientes clases en PIIPOO: CLASS INTERFACE cA; PUBLIC METHODS FUNCTION f (A : cA) : cA; OPERATOR := (A : cA); END CLASS INTERFACE cA, CLASS INTERFACE cB INHERITS FROM cA; PUBLIC METHODS FUNCTION f (B : cB) : cB; OPERATOR := (B : cB); END CLASS INTERFACE cB, y las siguientes declaraciones de objetos: A : cA; B : cB; ¿Cuáles de las siguientes expresiones son correctas y cuáles no? Razone las respuestas. a) B:= A . f(A); Correcta. Se ejecuta la función f de la clase cA que recibe un objeto de la clase cA y devuelve un objeto de la clase cA; y el operador := de la clase cA (heredado por la clase cB) que recibe un objeto de la clase cA. b) B:= A . f(B); Incorrecta. La clase cA no tiene definida una función f que reciba como argumento un objeto de la clase cB. c) A:= B . f(A); Correcta. Se ejecuta la función f de la clase cA (heredada por la clase cB) que recibe un objeto de la clase cA y devuelve un objeto de la clase cA; y el operador := de la clase cA que recibe un objeto de la clase cA. d) A:= B . f(B); Incorrecta. La clase cA no tiene definido un operador := que reciba como argumento un objeto de la clase cB, que es lo que devuelve la función f de la clase cB que recibe un objeto de la clase cB. Página 3 de 10 Programación II Febrero 2007 8. ¿Qué es necesario para la implantación del polimorfismo en PIIPOO? Herencia e instanciación dinámica 9. ¿Qué cinco tipos de métodos se pueden definir en una clase en PIIPOO? Describa brevemente el cometido de cada tipo. PROCEDIMIENTOS. Pueden alterar el estado del objeto que recibe el mensaje, o el estado de los objetos que reciben como argumento. No devuelven nada. FUNCIONES. No alteran el estado del objeto que recibe el mensaje, ni el estado de los objetos que reciben como argumento. Devuelven objetos o punteros a objetos. OPERADORES. Proporcionan una notación más conveniente para expresar operaciones aritméticas o lógicas. Pueden ser procedimentales o funcionales. CONSTRUCTORES. Se invocan automáticamente cada vez que se instancia un objeto de una clase y sirven para dar valores iniciales a los atributos del objeto creado. DESTRUCTORES. Se invocan automáticamente cada vez que se destruye un objeto de una clase y sirven para realizar cualquier tarea de limpieza que deba hacerse en ese momento, como por ejemplo liberar la memoria dinámica creada por el objeto que se destruye. 10. Dada las siguientes declaraciones: CLASS INTERFACE cA; PUBLIC METHODS PROCEDURE m1; DEFERRED PROCEDURE m2; END CLASS INTERFACE cA; CLASS IMPLEMENTATION cA; METHODS DEFINITION PROCEDURE m1; BEGIN SELF.m2 END; END CLASS INTERFACE cA; CLASS INTERFACE cB; INHERITS FROM cA; PUBLIC METHODS REDEFINED PROCEDURE m2; END CLASS INTERFACE cB; CLASS INTERFACE cC; INHERITS FROM cA; PUBLIC METHODS REDEFINED PROCEDURE m2; END CLASS INTERFACE cC; ¿Son correctos los siguientes grupos de sentencias? En caso afirmativo, ¿qué métodos se ejecutarían? En caso negativo, justifique su respuesta a) p : ^cA; NEW (p, cC); p^.m1; Incorrecta. El puntero no es polimórfico y no admite direcciones de objetos de la clase cC. b) p : ^cA; NEW (p, cA); p^.m1; Incorrecta. No se puede crear un objeto de la clase cA por ser una clase abstracta. c) p : ^cB; NEW (p, cB); p^.m1; Correcta, Se ejecutan el metodo m1 definido en la clase cA y heredado por cB y el método m2 definido en la clase cB. d) p : POLYMORPHIC ^cA; NEW (p, cB); p^.m1; Correcta, Se ejecutan el metodo m1 definido en la clase cA y heredado por cB y el método m2 definido en la clase cB. Página 4 de 10 Programación II Febrero 2007 III. PROGRAMACIÓN FUNCIONAL 11. Enumere las desventajas de la programación funcional. Dificultad de escribir código e ineficiencia en su ejecución. 12. ¿Cuáles de las siguientes líneas responden a posibles tipos de una función CAML?. Razone las respuestas. a) [char] -> [char] b) (int , int) -> int c) _ * _ -> bool -> true d) int a) Incorrecto. [char] no es un tipo. Debería ser char list -> char list b) Incorrecto. (int, int) no es un tipo. Debería ser int * int -> int c) Incorrecto. _ * _ no es un tipo. Debería ser ‘a * ‘b -> bool d) Incorrecto. true no es un tipo. Debería ser int -> bool 13. ¿Es correcta la siguiente función? En caso afirmativo, infiera su tipo y escríbalo en la notación CAML. En caso contrario, justifique la respuesta. let rec f = function 1 -> (1,0) | n -> (n, f(n-1));; No es correcta. En el caso base la función devuelve una tupla de dos enteros, y en el caso general devuelve una tupla formada por un entero y una tupla. 14. ¿Son correctos los siguientes patrones en el lenguaje CAML? En caso afirmativo, indique qué valores satisfacen el patrón. En caso negativo, razone la respuesta. a) (_,_)::_::_ b) _::(_,_)::_ c) _::_::(_,_) Correcto. Se satisface con cualquier lista con al menos dos tuplas de dos elementos de cualquier tipo. Correcto. Se satisface con cualquier lista con al menos dos tuplas de dos elementos de cualquier tipo. Incorrecto. A la derecha del operador :: debe aparecer una lista, no una tupla. 15. ¿Qué tipo de recursividad posee la siguiente función? Razone su respuesta. let rec f = function 0 -> 1 | x -> if x > 0 then x*f(x-1) else x*f(x+1);; Recursividad lineal, porque en cada aplicación de la función se realiza como máximo una llamada recursiva a la propia función. Página 5 de 10 Programación II Febrero 2007 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 FEBRERO Plan: 92 / Curso: 2006-2007 Madrid, a 6 de Febrero de 2007 Fechas de Publicación de Notas y de Revisión de Exámenes Publicación de Notas Miércoles 21 de Febrero de 2007 Revisión de Examen y Prácticas: Viernes 23 de Febrero de 2007 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/ProgramacionII/Notas.htm PROBLEMA 1: PROGRAMACIÓN CONCURRENTE Puntuación: 2'5 puntos En un cierto programa concurrente hay NumProcesos procesos del siguiente tipo: PROCESS TYPE TProceso (prioridad : INTEGER); BEGIN A END; donde el parámetro prioridad indica la prioridad de cada proceso para ejecutar el bloque de instrucciones A, y está comprendido entre los valores 1 y MaxPrioridad. Además se sabe que hay al menos un proceso de cada prioridad. SE PIDE: Añadir todo el código de sincronización necesario en los procesos para que se cumplan los siguientes requisitos: - Todo proceso con una cierta prioridad debe ejecutar A antes de cualquier otro proceso de prioridad inferior a la suya. - Todos los procesos con la misma prioridad deben poder ejecutar A concurrentemente. Para cumplir estos requisitos, puesto que inicialmente se desconoce el número de procesos que hay de cada prioridad, deben ser los propios procesos los que cooperen durante su ejecución para calcular cuántos procesos existen de cada prioridad mediante un array compartido del siguiente tipo: TYPE tCuantos = ARRAY [1..MaxPrioridad] OF INTEGER; y ningún proceso debe ejecutar A hasta que se haya terminado de calcular cuántos procesos existen de cada prioridad. Página 6 de 10 Programación II Febrero 2007 SOLUCION CON MONITORES: MONITOR Sincro; EXPORT PreA, PostA; TYPE tCuantos = ARRAY [1..MaxPrioridad] OF INTEGER; VAR cuantosPrioridad : tCuantos; cuantosTotal : INTEGER; esperaPrioridad : ARRAY [1..MaxPrioridad] OF CONDITION; (*--------------------------------------------------------------------------*) PROCEDURE PreA (prioridad : INTEGER); BEGIN cuantosPrioridad[prioridad] := cuantosPrioridad[prioridad] + 1; cuantosTotal := cuantosTotal + 1; (* Comprobar si es el ultimo proceso de todos *) IF cuantosTotal < NumProcesos THEN DELAY(esperaPrioridad[prioridad]) ELSE BEGIN (* Despertar a todos los procesos de la maxima prioridad *) WHILE NOT EMPTY(esperaPrioridad[MaxPrioridad]) DO RESUME(esperaPrioridad[MaxPrioridad]); (* Comprobar si este proceso debe bloquearse *) IF prioridad < MaxPrioridad THEN DELAY(esperaPrioridad[prioridad]) END END; (*--------------------------------------------------------------------------*) PROCEDURE PostA (prioridad : INTEGER); BEGIN cuantosPrioridad[prioridad] := cuantosPrioridad[prioridad] - 1; (* Comprobar si es el ultimo proceso con esta prioridad y no es de la minima prioridad *) IF (cuantosPrioridad[prioridad] = 0) AND (prioridad > 1) THEN (* Despertar a todos los procesos de la siguiente prioridad *) WHILE NOT EMPTY(esperaPrioridad[prioridad - 1]) DO RESUME(esperaPrioridad[prioridad - 1]) END; (*--------------------------------------------------------------------------*) VAR i : INTEGER; BEGIN FOR i := 1 TO MaxPrioridad DO cuantosPrioridad[i] := 0; cuantosTotal := 0 END; (****************************************************************************) Página 7 de 10 Programación II Febrero 2007 PROCESS TYPE TProceso (prioridad : INTEGER); BEGIN Sincro.PreA(prioridad); A; Sincro.PostA(prioridad) END; SOLUCION CON SEMAFOROS: TYPE tCuantos = ARRAY [1..MaxPrioridad] OF INTEGER; TYPE tSincro = RECORD cuantosPrioridad : tCuantos; cuantosTotal : INTEGER; exclusion : SEMAPHORE; esperaPrioridad : ARRAY [1..MaxPrioridad] OF SEMAPHORE END; (*--------------------------------------------------------------------------*) PROCEDURE PreA (prioridad : INTEGER; VAR sincro : tSincro); VAR i : INTEGER; BEGIN WAIT(sincro.exclusion); sincro.cuantosPrioridad[prioridad] := sincro.cuantosPrioridad[prioridad] + 1; sincro.cuantosTotal := sincro.cuantosTotal + 1; (* Comprobar si es el ultimo proceso de todos *) IF sincro.cuantosTotal = NumProcesos THEN (* Despertar a todos los procesos de la maxima prioridad *) FOR i:=1 TO sincro.cuantosPrioridad[MaxPrioridad] DO SIGNAL(sincro.esperaPrioridad[MaxPrioridad]) SIGNAL(sincro.exclusion); WAIT(sincro.esperaPrioridad[prioridad]) END; (*--------------------------------------------------------------------------*) PROCEDURE PostA (prioridad : INTEGER; VAR sincro : tSincro); VAR i : INTEGER; BEGIN WAIT(sincro.exclusion); sincro.cuantosPrioridad[prioridad] := sincro.cuantosPrioridad[prioridad] - 1; (* Comprobar si es el ultimo proceso con esta prioridad y no es de la minima prioridad *) IF (sincro.cuantosPrioridad[prioridad] = 0) AND (prioridad > 1) THEN (* Despertar a todos los procesos de la siguiente prioridad *) FOR i:=1 TO sincro.cuantosPrioridad[prioridad - 1] DO SIGNAL(sincro.esperaPrioridad[prioridad - 1]) SIGNAL(sincro.exclusion) END; (****************************************************************************) Página 8 de 10 Programación II Febrero 2007 PROCESS TYPE TProceso (prioridad : INTEGER; VAR sincro : tSincro); BEGIN PreA(prioridad, sincro); A; PostA(prioridad, sincro) END; (****************************************************************************) VAR sincro : tSincro; i : INTEGER; BEGIN FOR i := 1 TO MaxPrioridad DO BEGIN sincro.cuantosPrioridad[i] := 0; INITIAL(sincro.esperaPrioridad[i], 0) END; sincro.cuantosTotal := 0; INITIAL(sincro.exclusion, 1); ............... END. PROBLEMA 2: PROGRAMACIÓN FUNCIONAL Puntuación: 2'5 puntos Defina la función MayorMenores que recibiendo como entrada una lista no vacía de listas de enteros no vacías, devuelva el mayor elemento de los menores elementos de cada una de las sublistas que componen la lista de entrada. Ejemplos: # # # # - MayorMenores : int = 1 MayorMenores : int = 5 MayorMenores : int = 3 MayorMenores : int = 5 [[2;1;3]];; [[2;1;3];[1];[3;4;2];[3;4;5];[5;5;5]];; [[2;1;3];[1];[3;4;2];[3;4;5];[-5;5;5]];; [[-2;-1;-3];[1];[3;-2;4];[3;-4;5];[5;5;5]];; SOLUCION: (* Solucion 1 **************************************************************) let rec Menor = function [ele] -> ele | ele::cola -> if ele <= Menor(cola) then ele else Menor(cola);; let rec Mayor = function [ele] -> ele | ele::cola -> if ele >= Mayor(cola) then ele else Mayor(cola);; let rec Menores = function [] -> [] | lista::resto -> Menor(lista)::Menores(resto);; let MayorMenores = function lista -> Mayor(Menores(lista));; Página 9 de 10 Programación II Febrero 2007 (* Solucion 2 **************************************************************) let rec Menor = function [ele] -> ele | ele::cola -> if ele <= Menor(cola) then ele else Menor(cola);; let rec MayorMenores = function [lista] -> Menor(lista) | lista::cola -> if Menor(lista) >= MayorMenores(cola) then Menor(lista) else MayorMenores(cola);; Página 10 de 10