Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós 1. Equivalencia de herramientas. Implemente las primitivas de los buzones mediante monitores.(2pt). monitor mibuzon; const MAXBUZON = ...; export send, receive, empty; var buffer : array[1..MAXBUZON] of item; lleno, vacio : condition; frente, cola, nelem : int; procedure send(cosa : item); begin if (nelem = MAXBUZON) then delay(lleno); buffer[frente] := cosa; frente := (frente + 1) mod MAXBUZON; resume(vacio); end procedure receive(var cosa : item); begin if (frente = cola) then delay(vacio); cosa := buffer[cola]; cola := (cola + 1) mod MAXBUZON; resume(lleno); end funcion empty : bool; begin return (frente = cola); end; begin frente := 0; cola := 0; nelem := 0; end; 2. Se dice que un número natural mayor que cero es un número perfecto si es la suma de todos sus divisores excepto él. Por ejemplo, los divisores de 6 son 1,2,3 y 6. Como 1+2+3=6, 6 es un número perfecto. Vamos a hacer un programa con una estructura determinada que calcule los números perfectos entre 1 y n mediante paso de mensajes. 1 Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós Cada número, i, entre 1 y n, va estar representado por un proceso al que llamaremos proceso i-ésimo. El proceso i-ésimo hará lo siguiente: Para k, que variará entre los múltiplos de i menores o iguales que n pero distintos del propio i, el proceso enviará un mensaje al proceso k-ésimo cuyo contenido es i. Por otra parte, también recibirá los mensajes de sus compañeros e irá sumando la información de los mensajes recibidos para formar la suma de sus divisores. El proceso i-ésimo también enviará un mensaje a todos los procesos j-ésimos, con j > i, con el contenido ”0” para marcar el final de la comunicación con ese proceso. Cuando un proceso i-ésimo haya recogido el número adecuado de mensajes con contenido nulo, sabrá que ha recibido todos los mensajes que necesitaba. En ese momento enviará la información de si es un número perfecto o no a un proceso controlador y terminará. El proceso controlador recibirá los mensajes de los procesos, imprimirá por pantalla quiénes son los números perfectos y cuando los haya imprimido todos terminará. Escriba un programa concurrente en pseudocódigo para modelizar el cálculo descrito, utilizando exactamente dos tipos de proceso: i-ésimo y controlador. No puede utilizar memoria compartida. Si en la práctica obligatoria de la asignatura utilizó semáforos, utilice la invocación remota. Si en la práctica obligatoria de la asignatura utilizó monitores, entonces utilice buzones. Si utilizó semáforos y monitores juntos entonces está usted suspenso en esta convocatoria y puede volver a realizar la práctica para la convocatoria de septiembre. La solución debe contar con unas estructuras de datos que permitan resolver cabalmente el problema. Se prestará atención para evitar situaciones de interbloqueo, inanición y espera activa. Asimismo, se debera procurar alcanzar un alto grado de concurrencia entre los procesos y una correcta sincronización entre los mismos. Si se identifica un problema-tipo, debe mencionarse explícitamente (incluyendo, en su caso, la prioridad más adecuada) antes de proceder con el pseudocódigo. Es muy importante que el comportamiento de los procesos se ajuste al enunciado, tanto en los aspectos específicamente concurrentes como en los demás. (8pt). Este sería el programa mediante invocación remota: program perfecto; const N = 1000000; process type k-esimo(k : int) var i, nceros, suma : int; begin 2 Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós i := 2; nceros := 0; suma := 0; // Enviamos los mensajes a los multiplos mientras no tengamos // invocaciones de otros procesos, si las hay las atendemos primero while i*k <N do select accept enviar(h : int) do begin suma := suma + h; if h = 0 then nceros := nceros + 1; end else begin k-esimo[i*k].enviar(k); i := i + 1; end end-select i := k+1; // Enviamos los mensajes de fin de comunicacion mientras no haya llamadas // remotas que atender while i <= N do select accept enviar(h : int) do begin suma := suma + h; if h = 0 then nceros := nceros + 1; end else begin k-esimo[i].enviar(0); i := i+1; end; end-select // Atendemos las ultimas llamadas while nceros <>k - 1 do begin accept enviar(h : int) do begin 3 Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós suma := suma + h; if h = 0 then nceros := nceros +1; end end; // Si el numero es perfecto avisamos al controlador if (suma = k) then controlador.perfecto(k); end; process controlador; begin repeat select accept perfecto(h : int) do writeln(’El numero ’, h, ’ es perfecto’); or terminate end-select forever end; numeros : array[1..N] of k-esimo; cobegin controlador; for i := 1 to N do numeros[i](i); coend end. Y este sería el programa mediante buzones program perfecto; const N = 1000000; // Cualquier valor entre 1 y 2*N es adecuado. Cuanto mayor el tamaño dentro de // esos limites, mayor sera la concurrencia TAMBUZON=...; var buzones : array[1..N] of mailbox[TAMBUZON] of int; control : mailbox[1] of int; i : int; 4 Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós // El proceso que representa al numero k-esimo process type k-esimo(k : int); var i, h, nceros, suma : int; begin i := 2; nceros := 0; suma := 0; // Vamos a enviar los mensajes a los multiplos. // Intercalamos la recepcion de mensajes para aumentar la concurrencia while i*k <N do begin send(buzones[i*k], k); if not empty(buzones[k]) begin receive(buzones[k], h); suma := suma + h; if h = 0 then nceros := nceros + 1; end; i := i + 1; end // Ahora enviamos el mensaje de fin de comunicacion a los numeros mayores que k // Tambien intercalamos la recepcion de mensajes para aumentar la concurrencia i := k + 1; while i <= N do begin send(buzones[i], 0); if not empty(buzones[k]) begin receive(buzones[k], h); suma := suma + h; if h = 0 then nceros := nceros + 1; end; i := i + 1; end; // Y recibimos los ultimos mensajes while nceros <>k - 1 do begin 5 Examen de Programación Concurrente: Segunda Semana Febrero 2008 David Fernández Amorós receive(buzones[k], h); suma := suma + h; if h = 0 then nceros := nceros + 1; end; if suma = k then send(control, k); end. numeros : array[1..N] of k-esimo; process controlador; var k : int; begin repeat select receive(control, k); writeln(’El número ’,k, ’ es perfecto.’); or terminate end-select forever end; cobegin controlador; for i := 1 to N do numeros[i](i); coend end. 6