PROBLEMAS CLÁSICOS. EL PROBLEMA DE LOS FILÓSOFOS COMENSALES. Cinco filósofos pasan su vida pensando y comiendo. Los filósofos comparten una mesa circular rodeada por cinco sillas, una para cada uno de ellos. En el centro de la mesa se encuentra una fuente de arroz, y también sobre la mesa hay cinco palillos chinos. Cuando un filósofo piensa, no interactúa con sus colegas. Ocasionalmente, un filósofo tiene hambre y trata de coger los dos palillos que están más cerca de él (los palillos colocados entre él y sus vecinos de la derecha y de la izquierda). Un filósofo sólo puede coger un palillo a la vez y, obviamente, no puede ser el que está en la mano de un vecino. Cuando un filósofo hambriento tiene sus dos palillos al mismo tiempo come sin soltarlos. Cuando termina de comer, coloca ambos palillos sobre la mesa y comienza a pensar otra vez. La situación de los Filósofos comensales. El problema de los filósofos comensales se considera un problema de sincronización clásico, pero no por su importancia práctica sino porque es un ejemplo de una gran clase de problemas de control de concurrencia. Una solución sencilla consiste en representar cada palillo con un semáforo. Un filósofo trata de coger el palillo ejecutando una operación wait en ese semáforo; suelta sus palillos ejecutando signal en los semáforos correspondientes. Así, los datos compartidos son: var palillo:array [0..4] of semáforo; donde todos los elementos de palillo reciben un valor inicial de 1. A continuación se presenta un programa que simula esta situación. program Filo01; (* Filosofos comensales - semáforos versión 1 *) const N = 5; var palillo : array [1..N] of semaphore; (* binario *) I : integer; process type filosofos(numero : integer); begin repeat writeln('Pensando el ',numero); sleep(random(5)); (* PENSANDO *) wait(palillo[numero]); wait(palillo[(numero mod N) + 1]); writeln('Comiendo el ',numero); sleep(random(5)); (* COMIENDO *) signal(palillo[numero]); signal(palillo[(numero mod N) + 1]); forever end; (* filosofos *) var procfil: array[1..N] of filosofos; begin for I := 1 to N do initial(palillo[I],1); cobegin for I := 1 to N do procfil[I](I); coend end. - Pascal-FC for IBM PC compatibles - Compiler Version P5.2 G L Davies & A Burns, University of Bradford Compiling filo01 ... Compilation complete 1 - Interpreter Version P5.3 Program filo01 ... execution begins ... Pensando Pensando Pensando Pensando Comiendo Pensando Pensando Comiendo Comiendo Comiendo Pensando Pensando el el el el el el el el el el el el 1 5 2 3 1 4 1 2 4 1 2 1Pensando el 4Comiendo el 3 Comiendo el 5 Comiendo el 2 Pensando el Comiendo el 4 3 Pensando el 5 Comiendo el Pensando el 2 1 Comiendo el 3 Pensando el 4 Comiendo el 5 Pensando el 1 Pensando el Comiendo el 2 3 Pensando el 2 Comiendo el 4 Pensando el 4 Pensando el 5 Comiendo el 1 Comiendo el 3 Comiendo el 5 Pensando el 1 Pensando el 5 Comiendo el 2 Pensando el 3 Aunque esta solución garantiza que dos vecinos no pueden comer simultáneamente, hay que rechazarla porque existe la posibilidad de crear un bloqueo mutuo. Suponga que los cinco filósofos tienen hambre al mismo tiempo y cada uno coge el palillo que está a su izquierda; todos los elementos del arreglo palillo serán iguales a cero. Cuando cada filósofo trata de coger el palillo a su derecha, su ejecución se aplazará eternamente. A continuación se presentan varias posibles soluciones, con diferentes algoritmos y con diferentes elementos del lenguaje para la sincronización de procesos. Se aclara que cualquier solución satisfactoria para este problema debe eliminar la posibilidad de que uno de ellos muera de hambre. Una solución libre de bloqueos mutuos no la elimina necesariamente. Permitir que cuatro filósofos como máximo, se sienten a comer al mismo tiempo. program Filo02; (* Filósofos comensales - semáforos versión 2 *) const N = 5; var palillo : array [1..N] of semaphore; (* binario *) sillaslibre : semaphore; (* general *) I : integer; process type filosofos(numero : integer); begin repeat 2 writeln('Pensando el ',numero:2); sleep(random(5)); (* PENSANDO *) wait(sillaslibre); wait(palillo[numero]); wait(palillo[(numero mod N) + 1]); writeln('Comiendo el ',numero:2); sleep(random(5)); (* COMIENDO *) signal(palillo[numero]); signal(palillo[(numero mod N) + 1]); signal(sillaslibre) forever end; (* filosofos *) var procfil: array[1..N] of filosofos; begin for I := 1 to N do initial(palillo[I],1); initial(sillaslibre,N - 1); cobegin for I := 1 to N do procfil[I](I); coend end. - Pascal-FC for IBM PC compatibles - Compiler Version P5.2 G L Davies & A Burns, University of Bradford Compiling filo02 ... Compilation complete - Interpreter Version P5.3 Program filo02 ... execution begins ... Pensando Pensando Pensando 1 Comiendo 5 Pensando Comiendo Comiendo Comiendo Pensando Comiendo Pensando Comiendo 5 Pensando Pensando Comiendo Comiendo Pensando Comiendo Pensando Comiendo Comiendo Pensando Pensando Comiendo Pensando Comiendo Comiendo 3 el Pensando el el 4 el Pensando el el 3 4 el 4 el 4 el 2 el 1 el 2 el 3 el 4 el Pensando el el el el el el el el el el el el el el el el 2 3 5 3 2 3 4 4 4 1 2 1 3 4 5 2 1 Pensando el 3 Pensando el 2 Comiendo el 4 Pensando el 5 Comiendo el 1 Pensando el 1 Comiendo el 3 Pensando el 4Comiendo el 2 Pensando el 3 Comiendo el 4 Comiendo el 1 Pensando el 2 Comiendo el 3 Pensando el 4 Pensando el Comiendo el 5 1 Comiendo el 2 Pensando el 3 Pensando el Comiendo el 4 5 Comiendo el 1 Pensando el 2 Comiendo el 3 Pensando el 4 Comiendo el 5 Pensando el 1 Comiendo el 2 Pensando el 3 Permitir que un filósofo coja sus palillos sólo si los dos están disponibles (observe que esto debe hacerse en una sección crítica). program Filo03; (* Filósofos comensales: *) version monitor var j, num: integer; monitor palillomon; export getpalillo, putpalillo; var palillo: array [0..4] of integer; okparacomer: array [0..4] of condition; i: integer; procedure getpalillo(i: integer); begin if palillo[i] <> 2 then begin writeln('Filosofo ',i:2,' esta esperando'); delay(okparacomer[i]) end; palillo[(i+1) mod 5] := palillo[(i+1) mod 5] - 1; palillo[(i+4) mod 5] := palillo[(i+4) mod 5] - 1; writeln('Filosofo ',i:2,' come') end; (* getpalillo *) procedure putpalillo(i: integer); begin writeln('Filosofo ',i:2,' termina'); palillo[(i+1) mod 5] := palillo[(i+1) mod 5] + 1; palillo[(i+4) mod 5] := palillo[(i+4) mod 5] + 1; 4 if palillo[(i+1) mod 5] = 2 then resume(okparacomer[(i+1) mod 5]); if palillo[(i+4) mod 5] =2 then resume(okparacomer[(i+4) mod 5]) end; (* putpalillo *) begin (* cuerpo del monitor *) for i := 0 to 4 do palillo[i] := 2 end; (* palillomon *) procedure piensa; begin null end; (* piensa *) procedure come(n: integer); begin palillomon.getpalillo(n); sleep(1); palillomon.putpalillo(n) end; (* come *) process type tipofil(n: integer); begin repeat piensa; come(n) forever end; (* filosofo *) var filosofo: array[0..4] of tipofil; begin (* principal *) cobegin for num := 0 to 4 do filosofo[num](num) coend end. - Pascal-FC for IBM PC compatibles - Compiler Version P5.2 G L Davies & A Burns, University of Bradford Compiling filo03 ... Compilation complete - Interpreter Version P5.3 Program filo03 ... execution begins ... Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo 5 0 4 1 2 3 2 3 0 1 2 0 come esta esperando esta esperando come esta esperando termina come termina come esta esperando esta esperando Filosofo 1 termina Filosofo 0 come Filosofo 3 termina Filosofo 2 come Filosofo 1 esta esperando Filosofo 3 esta esperando Filosofo 0 termina Filosofo 4 come Filosofo 2 termina Filosofo 1 come Filosofo 0 esta esperando Filosofo 2 esta esperando Filosofo 4 termina Filosofo 3 come Filosofo 1 termina Filosofo 0 come Filosofo 4 esta esperando Filosofo 1 esta esperando Filosofo 0 termina Filosofo 1 come Filosofo 3 termina Filosofo 4 come Filosofo 0 esta esperando Filosofo 3 esta esperando Filosofo 1 termina Filosofo 2 come Filosofo 4 termina Filosofo 0 come Filosofo 1 esta esperando Filosofo 4 esta esperando Filosofo 2 termina Filosofo 3 come Filosofo 0 termina Filosofo 1 come Filosofo 2 esta esperando Filosofo 0 esta esperando Filosofo 3 termina Filosofo 4 come Filosofo 1 termina Filosofo 2 come Filosofo 3 esta esperando Filosofo 1 esta esperando Filosofo 4 termina Filosofo 0 come Filosofo 2 termina Filosofo 3 come Filosofo 4 esta esperando Filosofo 2 esta esperando Filosofo 0 termina Solución similar a la anterior pero usando recursos. program Filo04; (* Filosofos comensales: *) version recursos var j, num: integer; resource palcontrol; export getpalillo, putpalillo; var palillo: array [0..4] of integer; 6 i: integer; barrera1: boolean; guarded procedure esperando1(i: integer) when not barrera1; forward; guarded procedure esperando2(i: integer) when barrera1; forward; guarded procedure getpalillo(i: integer) when true; begin if palillo[i] <> 2 then if barrera1 then requeue esperando1(i) else requeue esperando2(i); palillo[(i+1) mod 5] := palillo[(i+1) mod 5] - 1; palillo[(i+4) mod 5] := palillo[(i+4) mod 5] - 1; writeln('Filosofo ',i:2,' come') end; (* getpalillo *) procedure putpalillo(i: integer); begin writeln('Filosofo ',i:2,' termina'); palillo[(i+1) mod 5] := palillo[(i+1) mod 5] + 1; palillo[(i+4) mod 5] := palillo[(i+4) mod 5] + 1; barrera1 := not barrera1 end; (* putpalillo *) guarded procedure esperando1; begin requeue getpalillo(i) end; guarded procedure esperando2; begin requeue getpalillo(i) end; begin (* cuerpo del recurso barrera1 := true; for i := 0 to 4 do palillo[i] := 2 end; (* palcontrol *) *) procedure piensa; begin null end; (* piensa *) procedure come(n: integer); begin palcontrol.getpalillo(n); sleep(1); palcontrol.putpalillo(n) end; (* come *) process type tipofil(n: integer); begin repeat piensa; come(n) forever end; (* filosofo *) var filosofo: array[0..4] of tipofil; 7 begin (* principal *) cobegin for num := 0 to 4 do filosofo[num](num) coend end. - Pascal-FC for IBM PC compatibles - Compiler Version P5.2 G L Davies & A Burns, University of Bradford Compiling filo04 ... Compilation complete - Interpreter Version P5.3 Program filo04 ... execution begins ... Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo 8 2 0 0 4 2 1 4 3 1 0 3 2 0 4 2 1 1 2 4 0 2 3 0 1 1 0 3 2 0 4 2 1 4 3 3 4 1 2 4 0 0 4 2 1 1 come come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo 2 4 0 0 4 2 1 1 2 4 0 0 4 2 1 4 3 1 0 3 2 0 4 4 0 2 3 3 2 0 4 2 come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina come termina program Filo05; (* Filósofos comensales usando CANALES *) const nfil = 5; maxfil = 4; type canalsyn = array[0..maxfil] of channel of synchronous; var ind: integer; getpalillo,putpalillo: canalsyn; procedure piensa; begin null end; procedure come; begin null end; process type tipofil(n: integer); begin repeat piensa; getpalillo[n] ! any; come; putpalillo[n] ! any; forever end; (* filosofo *) 9 process palcontrol; var palillo: array[0..maxfil] of integer; i: integer; begin for i := 0 to maxfil do palillo[i] := 2; repeat select for i := 0 to maxfil replicate when palillo[i] = 2 => getpalillo[i] ? any; palillo[(i+1) mod nfil]:=palillo[(i+1) palillo[(i+4) mod nfil]:=palillo[(i+4) writeln('Filosofo ',i:1,' come'); or for i := 0 to maxfil replicate putpalillo[i] ? any; palillo[(i+1) mod nfil]:=palillo[(i+1) palillo[(i+4) mod nfil]:=palillo[(i+4) writeln('Filosofo ',i:1,' piensa'); or terminate end forever end; (* palcontrol *) var filosofo:array[0..4] of tipofil; begin cobegin for ind := 0 to maxfil do filosofo[ind](ind); palcontrol coend end. - Pascal-FC for IBM PC compatibles - Compiler Version P5.2 G L Davies & A Burns, University of Bradford Compiling filo05 ... Compilation complete - Interpreter Version P5.3 Program filo05 ... execution begins ... Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo 10 4 2 4 2 4 2 2 4 3 1 3 4 4 1 0 0 0 0 come come piensa piensa come come piensa piensa come come piensa come piensa piensa come piensa come piensa mod nfil]-1; mod nfil]-1; mod nfil]+1 ; mod nfil]+1 ; Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo Filosofo 11 4 2 4 2 4 2 2 2 2 2 4 2 1 1 4 2 4 2 4 2 4 0 2 3 3 0 4 2 2 2 2 2 4 2 4 2 4 0 2 0 4 2 4 4 4 come come piensa piensa come come piensa come piensa come piensa piensa come piensa come come piensa piensa come come piensa come piensa come piensa piensa come come piensa come piensa come piensa piensa come come piensa come piensa piensa come come piensa come piensa