ejfilosofos

Anuncio
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
Descargar