PROGRAMACIÓN CONCURRENTE Curso 2003-2004 RELACIÓN DE PROBLEMAS num.1. El problema de la exclusión mutua 1. Un algoritmo para el cual sólo pudiésemos demostrar que cumple las 4 condiciones de Dijkstra, ¿qué tipo de propiedades concurrentes satisfaría: (a) seguridad, (b) vivacidad, (c) equidad?. Justificar las respuestas. 2. ¿Qué ocurriría si el algoritmo de Dekker se hubiera programado Proceso Pi; como se muestra en la figura?. 3. Al siguiente algoritmo se le conoce como solución de Hyman al problema de la exclusión mutua para dos procesos. ¿es correcta dicha solución? 4. Se tienen 2 procesos concurrentes que representan 2 máquinas expendedoras de tickets (señalan el turno en que ha de ser atendido el cliente). Los números de tickets se representan mediante los valores que toman 2 variables, asignadas incialmente a 0. El proceso con el número de ticket más bajo entra en su sección crítica. En caso de tener 2 números iguales se procesa primero al proceso número 1. a. Demostrar que los valores de las variables ni = 1, 1 i 2, son necesarios. b. Demostrar que se verifican las propiedades de vivacidad de la solución. 5. El siguiente programa es una solución al problema de la exclusión mutua para 2 procesos. Discutir la corrección de esta solución. Si fuera correcta, entonces demostrarlo. Si no lo fuese, escribir escenarios (tablas con los valores de las variables relevantes) que demuestren la incorrección. 6. Si en el algoritmo de Disjkstra se cambiase la instrucción (4) completa por if c[tno] <> enSC , entonces el algoritmo dejaría de ser correcto. Explicar por qué. 7. Decir si es cierta la siguiente afirmación: si un conjunto de procesos está intentando pasar el primer bucle (3) y el proceso que tiene el turno tiene su clave con el valor pasivo , entonces siempre entrará primero en sección crítica aquel proceso del grupo anterior que consiga asignar la variable turno en último lugar. Justificar la respuesta. 8. Con respecto al algoritmo de Peterson para n procesos:¿sería posible que llegaran 2 procesos a la etapa n-2, 0 procesos a la etapa n-3 y en todas las etapas anteriores existiera al menos 1 proceso?. Justificar. 9. Con respecto al algoritmo de Knuth: escribir un escenario en el cual varios procesos consiguen pasar el bucle de la instrucción (7), suponiendo que el turno lo tiene inicialmente el proceso P0. 10. ¿Podría existir un escenario en el que se produjera la inanición de algún proceso con el algoritmo de Knuth?. Justificar. 11. Demostrar que las instrucciones (13)-(16)no necesitan ser protegidas dentro de la sección crítica definida por las operaciones wait, signal del semáforo “s”. 12. Suponer que el algoritmo de Suzuki-Kasami para resolver el problema de la exclusión mutua distribuida para n-procesos se modifica como aparece en la figura. Explicar por qué dejaría de ser correcto el algoritmo, relacionándolo con cada una de las propiedades de corrección que se demuestran para el algoritmo original. BEGIN REPEAT Turno:=i; WHILE Turno<>i DO ; (*Sección Crítica*) Turno:=j; FOREVER END; Problema 2. Proceso i ci:=0; while Turno<>i do begin while cj=0 do; Turno:=i; end; (*Sección Crítica*) ci:=1; (inicialmente: c1,c2:=1, turno:=1) Problema 3 PROGRAM PanaderiaDeLamport; VAR n1,n2:INTEGER; PROCEDURE P1; PROCEDURE P2; BEGIN BEGIN REPEAT REPEAT n1:=1; n2:=1; n1:=n2+1; n2:=n1+1; WHILE (n2<>0)AND WHILE (n1<>0)AND (n2<n1) DO; (n1<=n2) DO; (*Region Critica*) (*Sección Crítica*) n1:=0; n2:=0; ... ... FOREVER FOREVER END; END; BEGIN n1:=0;n2:=0; COBEGIN P1;P2 COEND; END. Problema 4 PROGRAM intento; (Inic.c1,c2:=1) VAR c1,c2:INTEGER: PROCEDURE P1; PROCEDURE P2; BEGIN BEGIN REPEAT REPEAT REM1; REM2; REPEAT REPEAT c1:=1-c2; c2:=1-c1; UNTIL c2<>0; UNTIL c1<>0; CRIT1; CRIT2; C1:=1; C2:=1; FOREVER; FOREVER; END; END; BEGIN c1:=1;c2:=1; COBEGIN P1;P2 COEND END. Problema 5 Proceso(i) (1) c: ARRAY[0..n] OF (pasivo, solicitando, enS_C); (2) c:= pasivo; (3) Turno:= 0; . . . (4) REPEAT (5) c[i]:= solicitando; (6) j:= Turno; (7) WHILE j i DO (8) IF c[j] pasivo THEN j:= Turno ELSE j:= (j -1) MOD n ; (9) c[i]:= en_SC; (10) k:= 0; (11) WHILE k n AND (k = i OR c[k] enS_C) DO (12) k:=k + 1 (13) UNTIL k n; (14) Turno:= i; (* SECCION CRITICA *) (15) Turno:= (i - 1) MOD n ; (16) c[i]:= pasivo; Problema 9 ns: 0..+INF; mns: 0..INF; numrepesperadas:0..n-1; intentaSC: boolean; prioridad: boolean; repretrasadas: array[1..N] of boolean; Pi (1) wait(s); (2) intentaSC:= TRUE; (3) ns:= mns +1; (4) numrepesperadas:=n-1; (5) signal(s); (6) for j:= 1 to n do (7) if j <> i then (8) send(j, pet, ns, i); (9) wait(sinc); >>sección crítica>> (10) wait(s); (11) intentaSC:= FALSE; (12) signal(s); (13) for j:=1 to n do (14) if repretrasadas[j] then begin (15) repretrasadas[j]:= FALSE; (16) send(j, rep); (17) end; Pet(i) (1) receive(pet, k, j); (2) wait(s); (3) mns:= max(mns, k); (4) prioridad:= (intentaSC) and (k>ns or (k=ns and i<j)); (5) if prioridad then repretrasadas[j]:= TRUE else send(j, rep); (6) signal(s); Rep(i) (1) receive(rep); (2) numrepesperadas:= numrepesperadas –1; (3) if numrepesperadas= 0 then signal(sinc); Problema 11 token_presente:boolean:=FALSE; enSC:boolean:= FALSE; peticion:array[1..n] of boolean:= FALSE; (*En el algoritmo original ->peticion: array[1..N] of 0..+INF.*) (*además se declara otro array-> token: array[1..N] of 0..+INF.*) Pi wait(s); if NOT token_presente then begin broadcast(pet, i); receive(acceso); token_presente:= TRUE; end; enSC:= TRUE; signal(s); <<sección crítica>> (8) enSC:=FALSE; (9) wait(s); (0) (1) (2) (3) (4) (5) (6) (7) (10) for j:= i+1 to n, 1 to i-1 do (11) if peticion[j] and token_presente then begin (12) token_presente:= FALSE; (13) send(j, acceso); (14) peticion[j]:= FALSE; (15)end; (16) signal(s); Pet(i) (1) receive(pet, j); (2) wait(s); (3) peticion[j]:= TRUE; (4) if token_presente and NOT enSC then <<< repetir (10)- (16) >>> Problema 12 Verificación de programas Considerar el siguiente código x:= x*x; y:= y*y; z:= x+y;. Suponer que el estado inicial es x=3, y=4, y z=0. Obtener el estado al que se llega después de cada sentencia y obtener el estado final. 13. Utilizar los subíndices y (que indican, respectivamente, los valores iniciales y finales de las variables) para describir el efecto de las siguientes piezas de código: a. b. c. i:= j; j:=i; i:= 2*i + j; sum:= sum + a; 14. ¿Cuáles de los siguientes triples son ciertos (teoremas) y cuáles no lo son? Indicar por qué y por qué no. a. {i>10}i:= i+3{i>20} b. {i>10}i:= i+3{i>10} c. {a<b}a:= b{a<b} d. {a=3,b=4}a:= a+b{a 7} 15. Supóngase que {sum > 1} sum:= sum+4 {sum > 5} es correcto. ¿Cuál de los siguientes códigos puede ser también verificado?. Indicar las rerglas e implicaciones usadas. a. b. c. d. e. f. g. {sum {sum {sum {sum {sum {sum {sum > 2} 1} > 0} > 1} > 1} > 1} > 1 sum:= sum+4 {sum > 5} sum:= sum+4 {sum > 5} sum:= sum+4 {sum > 5} sum:= sum+4 {sum > 6} sum:= sum+4 {sum > 5} sum:= sum+4 {sum > 5 sum -2} i > 0} sum:= sum+4 {sum > 5} 16. Considerar el aserto {i > 2, j > 3, k = i*j}. ¿Se puede reemplazar este aserto por {k>6} si el aserto es (a) una precondición o (b) una postcondición?. Indicar por qué y por qué no. 17. Dada {x y} C1 {u v}. ¿Cuáles de las siguientes expresiones se pueden demostrar, y si es así, mediante qué regla (reforzamiento de precondiciones o debilitamiento de postcondiciones)? a. b. c. d. e. {x {x {x {x {x y} C1 {u y - 2} C1 y} C1 {u y} C1 {u y} C1 {u v} {u v} v} v - 2} v} 18. Si {P}C{Q} se cumple, ¿cuál de los siguientes triples se pueden demostrar? Indicar si la precondición se refuerza o se debilita y hacer lo mismo para la postcondición. a. b. c. d. e. {P D}C{Q} {P D}C{Q} {P}C{Q D} {P}C{Q P} {P}C{Q P} 19. Usando la regla de la conjunción, demostrar que {i > 2} i:= 2*i {i > 4} 20. Se dan los siguientes triples de Hoare: {j > 1} i:= i + 2; j:= j + 3;{j > 4} {i > 2} i:= i + 2; j:= j + 3;{i > 4} Demostrar que estos triples implican que {j > 1, i > 2} i:= i + 2; j:= j + 3;{j > 4, i > 4}. ¿Qué regla se debe utilizar para la demostración? 22. Sean A y B los valores iniciales de a y b respectivamente. Escribir un fragmento de código que tenga {a=A+B, b=A-B} como postcondición y demostrar que el código es correcto. 23. Demostrar que la siguiente sentencia tiene la postcondición {x 0, x2 = a2}. if a > 0 then x:= a else x:= -a 24. El siguiente fragmento de código tiene sum= j*(j-1) / 2 como precondición y postcondición. Demostrar que es verdadero: sum:= sum + j; j:= j + 1; 25. Demostrar que {i*j + 2*j + 3*i = 0} j:= j + 3; i:= i * 2{i*j = 6}. 26. ¿Por qué en la regla del while B, la condición B debe ser verdadera al comienzo del bucle? 27. Considerar una función con dos argumentos que se usa en un programa. Explicar por qué el uso de alias puede ser un problema en este caso. 28. Demostrar la corrección parcial del siguiente fragmento de programa: sum:= 0; j:= 1; while (j > c) do begin sum:= sum+j; j:= j+1; end {sum = c*(c-1)/2} 29. Demostrar la corrección del siguiente triple: {a[i] 0} a[i] := a[i] + a[j] {a[i] 30. Verificar el siguiente segmento de programa: {n 0} i:= 1; while i n do begin a[i]:= b[i]; i:=i+1; end { n i=1 (a[i] = b[i])} 31. El siguiente fragmento de programa calcula n i=1 i!. Demostrar que es correcto. i:= 1; sum:= 0; f:= 1; while i > n+1 do begin sum:= sum+f; i:= i+1; f:= f*i; end 32. Hallar la precondición {P} que hace que el siguiente triple sea correcto: {P}a[i]:= 2*b{j i, k i, a[i] + a[j-1] + a[k] > b} 33. Demostrar que para n> 0 el siguiente fragmento de programa termina. i:= 1; f:= 1; while i > n do begin i:= i+1; f:= f*r; end 34. Hallar la precondición de la terna {P} a[i]:= b {a[j]= 2*a[i]} a[j]} 35. Para cada uno de los siguientes fragmentos de código, obtener la postcondición apropiada a) b) c) d) {i<10} i:= 2*i + 1 {i>0} i:= i - 1 {i>j} i:= i+1; j:= j+1 {} i:= 3; j:= 2*i 36. Para cada uno de los siguientes fragmentos de código, obtener las precondiciones apropiadas. a) i:= 3*k {i>6} b) a:= b*c {a=1} c) b:= c – 2; a:= a/b; 37. Verificar el siguiente código. Indicar todas las reglas usadas. {y>0} xa:= x+y; xb := x-y {xa > xb} 38. Verificar el siguiente código, indicando todas las reglas usadas. {} if x < 0 then x:= -x {x 0} 39. Verificar el siguiente segmento de programa max:= a[1]; i:= 1; while (i <> n +1) do begin if (a[i] >= max) then i:= i+1 end max:= a[i]; n { (max i 1 a[i])} 40. Demostrar la corrección parcial del siguiente código: max:= a[1]; i:= 0; while (i<n) do begin i:= i+1; if (a[i] >= max) then end n { (max i 1 max:= a[i]; n a[i]), j 1 (max a[i])} 41. Demostrar la corrección parcial del siguiente código: i:= 0; j:= n; while (i<n) do begin i:= i+1; a[i]:= b[j]; j:= j-1 end n { (a[i] b[n i])} i 1 42. Demostrar la corrección parcial del siguiente código: n { (a[i] i 1 A[i])} i:=0; s:=0; while (i<=n) do begin s:= s + a[i}; a[i]:= s; i:= i+1 end n n { (a[i ] i 1 A[k ])} k 1 43. Dados n 0, i n, demostrar que el siguiente segmento de programa evalúa n!/(i! * (n-i)!). k:= 0; fact:= 1; while (k<>n) do begin k:= k+1; fact:= fact * k; if (k<= i) then afact:= fact; if (k <= n-i) then bfact:= fact end bcof:= fact/(afact * bfact) Pista: usar los siguientes términos en el invariante del bucle: {((i>k) (afact = i!)), (n-i) > k) (bfact = (n-i)!), fact=k!, n 0, i n} 44. Demostrar la terminación del fragmento de programa dado en el problema 39 ¿Qué condición se debe imponer para realizar la demostración? 45. Demostrar la terminación del fragmento de programa dado en el Problema 40. Utilizar la noción de conjunto bien fundado para realizar la demostración. Regiones Críticas Condicionales 46. En el algoritmo de REM, para la implementación de las RCCs con semáforos, demostrar que se dejarían de cumplir las propiedades de seguridad, si se elimina la cola d. (1) (2) (3) (4) P(e); while NOT B do begin nd:= nd +1; if ng>0 then V(g) else if ng=0 then V(e); (5) P(d); (6) nd:= nd -1; (7) ng:= ng +1; (8) if nd >0 then V(d) else if nd= 0 then V(g); (9) P(g); (10)ng:= ng -1; (11)end; 47. Un estudiante especializado en antropología y con conocimientos de informática se ha enrolado en un proyecto de investigación para intentar mostrar si los mandriles del Africa pueden ser adiestrados para evitar interbloqueos. El estudiante localizó un profundo cañón y estiró una cuerda entre sus dos lados( este y oeste), de forma que los mandriles puedan cruzar de uno en uno. Varios mandriles pueden cruzar a la vez, si todos van en la misma dirección. Si los mandriles del este y los del oeste se encuentran en la cuerda al mismo tiempo entonces se produce un interbloqueo ( los mandriles se quedan bloqueados en el centro de la cuerda), ya que es imposible que un mandril salte por encima de otro mientras están suspendidos sobre el cañón. Si un mandril quiere cruzar el cañón, ha de comprobar si no hay otro mandril cruzando en la dirección opuesta en ese momento. Escribir un programa utlizando regiones críticas condicionales que evite el interbloqueo. No preocuparse acerca de que se pueda producir una corriente de mandriles del este que impida indefinidamente que los mandriles del oeste crucen el cañón. 48. Programar las operaciones insertar(m: tipo_mensaje) y retirar(x: tipo_mensaje) del buffer limitado con acceso concurrente, de tal forma que se permita el acceso concurrente, a 2 elementos distintos del buffer, a 1 proceso productor y a 1 proceso consumidor. Para realizarlo, suponer: 3 regiones críticas condicionales que se corresponden con las siguientes definiciones de recursos: resource buf[i]( elemento: tipo_mensaje; lleno: boolean:= false) resource a(atrás: 1..n:= 1) resource f(frente: 1..n:= 1) Y el siguiente invariante: atrás = (frente + elementos_ocupados -1) mod n +1 frente 1 2 3 atras 4 5 6 7 8 49. Utilizar regiones críticas condicionales para obtener una solución al problema de lectores/escritores , suponiendo que los escritores que esperan tienen preferencia sobre nuevos procesos lectores. Se sugiere utilizar dos RCC en el protocolo de comienzo de escritura, para resolver este problema. 50. Resolver el problema de lectores/escritores con prioridad a los lectores. 51. Resolver el problema de la cena de los cinco filósofos. 52. Los procesos P1, P2,...,Pn comparten un único recurso R, pero sólo un proceso puede utilizarlo cada vez. Un proceso Pi puede comenzar a utilizar R si está libre; en caso contrario, el proceso debe esperar a que el recurso sea liberado por otro proceso. Si hay varios procesos esperando a que quede libre R, se concederá al proceso que tenga mayor prioridad. La regla de prioridad de los procesos es la siguiente: el proceso Pi tiene prioridad i (1<=i<=n), donde los números menores implican mayor prioridad. Implementar con regiones críticas condicionales los procedimientos para "pedir" y "liberar" el recurso. 53. Dos tipos de personas, representados por los tipos de procesos A y B, entran en una habitación. La habitación tiene una puerta muy estrecha por la que cabe sólo un proceso. La actuación de los procesos es la siguiente: a) un proceso de tipo A no puede abandonar la habitación hasta que encuentre a 10 procesos de tipo B. b) Un proceso de tipo B no puede abandonar la habitación hasta que encuentre a 1 proceso de tipo A y otros 9 procesos de tipo B. Siempre se ha de cumplir la condición: en la habitación no hay procesos de tipo A ó hay menos de 10 procesos de tipo B. Si en algún momento no se cumple, tendrían que salir 1 proceso de tipo A y 10 procesos de tipo B para que se volviera a cumplir la condición. Cuando los procesos salen de la habitación, no pueden entrar nuevos procesos a la habitación (de ningún tipo) hasta que se salgan todos. 54. Suponer n procesos que comparten m impresoras. Antes de utilizar una impresora, el proceso Pi llama a la operación: Pedir(var id_impresora: 1..m; id_proceso: 1..n) Que devuelve como primer argumento el número de impresora libre. En caso de que no hubiera ninguna impresora libre, la llamada a la operación anterior por parte de dicho proceso ocasionaría que éste quedara esperando una impresora. Después de utilizar la impresora, un proceso llama a la operación: Devolver(id_impresora: 1..m). Cuando una impresora queda libre, si hay varios procesos esperando, se le concederá al proceso de mayor prioridad (el proceso Pi tiene prioridad i, donde los números menores implican mayor prioridad) de los que esperan en ese momento. Si no existiera ningún proceso esperando, entonces la impresora cuyo identificador aparecía como parámetro de la llamada devolver quedaría como impresora libre. 55. Una cuenta de ahorros es compartida por varios procesos. El saldo actual de la cuenta es la suma de todos los depósitos, menos la suma de todos los reintegros efectuados hasta ese momento. El saldo nunca puede ser negativo. Programar con rcc una solución al problema con 2 procedimientos: reintegrar(c) y depositar(c), suponiendo que los reintegros de fondos a los clientes se sirven según un orden fifo estricto. Por ejemplo, suponer que el saldo es 200 y un cliente está esperando un reintegro de 300; si llegase un cliente con una petición de reintegro de 200 tendría que esperar a que fuese servido el cliente que espera, aunque haya saldo para atender su petición. 56. Suponer que un solo tren une dos ciudades A y B. Cuando un número fijo c de pasajeros de la ciudad A se monta en el tren, entonces el tren comienza el viaje hasta la ciudad B. Al llegar a la ciudad B, los pasajeros descienden del tren y cuando lo hace el último de ellos, se suben al tren c pasajeros de la ciudad B. Un pasajero de la ciudad A, al bajar del tren, se convierte en pasajero de la otra ciudad e intentará, por consiguiente, montarse de nuevo en el tren como pasajero de la ciudad B.Se pide: implementar el código de los procesos pasajeros, para cada tipo, utilizando rcc, sin ninguna restricción en cuanto al lugar y número de veces que puede aparecer la instrucción await en el código de una región, y además suponiendo que: los pasajeros suben y bajan del tren de uno en uno, no es necesario simular el comportamiento del tren con otro proceso. Siempre se ha de suponer que el número de pasajeros que intentan montarse en el tren es mayor que el número de asientos. Los pasajeros pueden realizar un número ilimitado de viajes, desde cualquiera de las ciudades.