P á g i n a 1 | 24
UNIVERSIDAD NACIONAL DE TRUJILLO
FACULTAD DE CIENCIAS FÍSICAS Y
MATEMÁTICAS
INGENIERIA INFORMTÁTICA
PROGRAMACIÓN LÓGICA
MONOGRAFÍA
PROBLEMA DE LA CENA DE LOS FILÓSOFOS
AUTORES
ABANTO VERA ANGÉLICA MARÍA
CRUZ PÉREZ MIGUEL ÁNGEL
TRUJILLO – PERÚ
2014
P á g i n a 2 | 24
INDICE
DEDICATORIA ........................................................................................................................... 3
INTRODUCCIÓN ........................................................................................................................ 4
1. MARCO TEORICO ......................................................................................................... 5
1.1. Enunciado del Problema ....................................................................................... 5
1.2. Objetivo .................................................................................................................... 5
1.3. Problemas ................................................................................................................ 6
1.3.1. Exclusión Mutua .......................................................................................... 6
1.3.2. Interbloqueo ................................................................................................. 6
1.3.3. Inanición ....................................................................................................... 7
1.3.4. No Apropiación ............................................................................................ 7
1.3.5. Espera Circular ........................................................................................... 7
1.4. Posibles soluciones ............................................................................................ 7
1.4.1. Por Turno Cíclico ........................................................................................ 8
1.4.2. Por Varios Turnos ....................................................................................... 8
1.4.3. Cola de Tenedores .................................................................................... 8
1.4.4. Resolución de conflictos de cola de tenedores ..................................... 8
1.4.5. El Portero del Comedor ............................................................................. 9
1.4.6. Solución del Camarero .............................................................................. 9
1.4.7. Jerarquía de Recursos .............................................................................. 9
1.5. Código en Prolog .............................................................................................. 10
CONCLUSIONES ................................................................................................................. 24
REFERENCIAS BIBLIOGRAFICAS .................................................................................. 24
P á g i n a 3 | 24
DEDICATORIA
Primero y antes que nada, dar gracias a Dios, por estar con nosotros en cada paso que damos,
y por haber puesto en nuestro camino a aquellas personas que han sido nuestro soporte y
compañía durante todo el periodo de estudio.
Agradecer hoy y siempre a nuestras familias por el esfuerzo realizado por ellos. El apoyo en mis
estudios, de ser así no hubiese sido posible. A nuestros padres y demás familiares ya que me
brindan el apoyo, la alegría y me dan la fortaleza necesaria para seguir adelante.
P á g i n a 4 | 24
INTRODUCCIÓN
El problema de la cena de los Filósofos es un problema clásico de las ciencias de la computación
propuesto por Edsger Wybe Dijkstra en 1965 para representar el problema de la sincronización
de uno o varios procesos en un sistema operativo.
Se trata de que los recursos sean utilizados de la manera más eficiente por todos los procesos
implicados. Hay algoritmos para solucionarlo pero todos los métodos pasan por asignar
prioridades y/o tiempos máximos de uso de los recursos.
La finalidad es demostrar que se presentarán problemas ante la falta de una apropiada
sincronización y evitar la peligrosa condición de carrera.
P á g i n a 5 | 24
1. MARCO TEORICO
1.1. Enunciado del Problema
Cinco filósofos se sientan alrededor de una mesa y pasan su vida cenando y pensando.
Cada filósofo tiene un plato de fideos y un tenedor a la izquierda de su plato. Para comer
los fideos son necesarios dos tenedores y cada filósofo sólo puede tomar los que están
a su izquierda o derecha. Si cualquier filósofo toma un tenedor y el otro está ocupado,
se quedará esperando, con el tenedor en la mano, hasta que pueda tomar el otro tenedor,
para luego empezar a comer.
Restricciones:
Si dos filósofos adyacentes toman el mismo tenedor se producirá una condición de
carrera; ya que ambos competirán por el mismo tenedor y uno de ellos tendrá que
quedarse sin comer.
Si todos los filósofos escogen el mismo tenedor al mismo tiempo, entonces todos se
quedarán esperando eternamente. Ya que nadie liberara el tenedor que les falta; se
interpreta de tal forma que todos los filósofos se morirán de hambre.
1.2. Objetivo
El objetivo consiste en encontrar un recurso que permita que los filósofos nunca se
mueran de hambre.
P á g i n a 6 | 24
1.3. Problemas
Crea un algoritmo que permita satisfacer:
• La exclusión mutua
• Evitar el interbloqueo
• Evitar la inanición
• No apropiación
1.3.1. Exclusión Mutua
Exclusión mutua es la capacidad de prohibir a los demás procesos realizar una
acción cuando un proceso haya obtenido el permiso.
Para el problema de los filósofos se debe lograr que 2 filósofos no puedan
emplear el mismo tenedor a la vez
1.3.2. Interbloqueo
Interbloqueo es un bloque permanente de un conjunto de procesos que compiten
por los recursos del sistema o bien se comunican unos con otros.
En este caso todos los filósofos están hambrientos al mismo tiempo, todos se
sientan, todos toman el tenedor a su izquierda y todos a intentar tomar al otro
tenedor que no estará.
P á g i n a 7 | 24
Llega un punto en el que P1 ha adquirido el recurso R1 y el proceso P2 ha adquirido
el recurso R2 y cada proceso necesita el otro recurso.
1.3.3. Inanición
Es una situación similar al interbloqueo pero las causas son diferentes.
En el interbloqueo, dos procesos llegan a un punto muerto (se bloquean) cuando
cada uno de ellos necesita un recurso que es ocupado por el otro.
En cambio, en este caso, uno o más procesos están esperando recursos
ocupados por otros procesos que no se encuentran necesariamente bloqueados.
1.3.4. No Apropiación
Los recursos no pueden ser extraídos de los procesos que los tienen hasta su
completa utilización.
1.3.5. Espera Circular
Existe una cadena circular de procesos en la cual cada uno de ellos mantiene a
uno o más recursos que son requeridos por el siguiente proceso de la cadena.
1.4. Posibles soluciones
Una solución óptima se considerará aquella que permita el que él número máximo de
filósofos pueda alimentarse a la vez, es decir, maximizar la concurrencia (dos a la vez
supuestamente para el caso de 5 filósofos).
P1: Proceso A
P2: Proceso B
R1: Recurso 1
R1: Recurso 2
P á g i n a 8 | 24
1.4.1. Por Turno Cíclico
Se empieza por un filósofo, que si quiere puede comer y después pasa su turno
al de la derecha. Cada filósofo sólo puede comer en su turno. Problema: si el
número de filósofos es muy alto, uno puede morir de hambre antes de su turno.
1.4.2. Por Varios Turnos
Se establecen varios turnos de tiempo fijo, el mismo se debe aproximar al tiempo
medio que tarda un filósofo en comer. Para hacerlo más claro supongamos que
cada filósofo que puede comer (en su turno) tiene una ficha que después pasa a
la derecha. Si por ejemplo hay 7 comensales podemos poner 3 fichas en
posiciones alternas (entre dos de las fichas quedarían dos filósofos).
1.4.3. Cola de Tenedores
Cada vez que un filósofo tiene un tenedor espera un tiempo aleatorio para
conseguir el segundo tenedor. Si en ese tiempo no queda libre el segundo
tenedor, suelta el que tiene y vuelve a ponerse en cola para sus dos tenedores.
Visto desde el otro lado, cada tenedor sólo puede tener dos filósofos en cola,
siempre los mismos.
Esto crea el problema comentado de que si todos quieren comer a la vez y todos
empiezan tomando el tenedor de su derecha se bloquea el sistema (deadlock).
1.4.4. Resolución de conflictos de cola de tenedores
Cada vez que un filósofo tiene un tenedor espera un tiempo aleatorio para
conseguir el segundo tenedor. Si en ese tiempo no queda libre el segundo
tenedor, suelta el que tiene y vuelve a ponerse en cola para sus dos tenedores.
Si un filósofo A suelta un tenedor (porque ha comido o porque ha esperado
demasiado tiempo con el tenedor en la mano) pero todavía desea comer, vuelve
a ponerse en cola para ese tenedor. Si el filósofo adyacente B está ya en esa
cola de tenedor (tiene hambre) lo toma y si no vuelve a cogerlo A.
P á g i n a 9 | 24
Es importante que el tiempo de espera sea aleatorio o se mantendrá el bloqueo
del sistema.
1.4.5. El Portero del Comedor
Se indica a los filósofos que abandonen la mesa cuando no tengan hambre y
que no regresen a ella hasta que vuelvan a estar hambrientos (cada filósofo
siempre se sienta en la misma silla). La misión del portero es controlar el número
de filósofos en la sala, limitando su número a n-1, pues si hay n-1 comensales
seguros que al menos uno puede comer con los dos tenedores.
1.4.6. Solución del Camarero
Una solución sencilla se logra mediante la introducción de un camarero en la
mesa. Los filósofos deben solicitar su permiso antes de tomar cualquier tenedor.
Debido a que el camarero es consciente de cual tenedor está en uso, es capaz
de arbitrar y evitar un deadlock.
1.4.7. Jerarquía de Recursos
Otra solución sencilla se logra mediante la asignación de un orden parcial, o
jerarquía, a los recursos (los tenedores, en este caso), y estableciendo la
convención de que todos los recursos se solicitarán en orden, y serán puestos
en libertad en orden inverso. En este caso, si cuatro de los cinco filósofos cogen
simultáneamente sus tenedores con el número más bajo, sólo el tenedor con el
número más alto seguirá sobre la mesa, por lo que el quinto filósofo no será
capaz de coger ningún tenedor.
Permitiendo comer a un filósofo que tendrá acceso a los dos tenedores.
P á g i n a 10 | 24
1.5. Código en Prolog
:- use_module(library(pce)).
dining_philosophers :-
new(D, window('Cena de los Filosofos')),
new(S, window('Cena de los Filosofos: Estadísticas')),
send(D, size, new(_, size(800,800))),
new(E, ellipse(400,400)),
send(E, center, point(400,400)),
send(D, display, E),
new(F1, fork(0)),
new(F2, fork(1)),
new(F3, fork(2)),
new(F4, fork(3)),
new(F5, fork(4)),
send_list(D, display, [F1,F2,F3,F4,F5]),
new(Waiter, waiter(F1, F2, F3, F4, F5)),
create_plate(P1, 0),
create_plate(P2, 1),
create_plate(P3, 2),
create_plate(P4, 3),
create_plate(P5, 4),
create_point(0, Pt1),
create_point(1, Pt2),
create_point(2, Pt3),
create_point(3, Pt4),
create_point(4, Pt5),
P á g i n a 11 | 24
new(Ph1, philosopher('Aristoteles', Waiter, P1, D, S, 0, Pt1, left)),
new(Ph2, philosopher('Kant', Waiter, P2, D, S, 1, Pt2, left)),
new(Ph3, philosopher('Spinoza', Waiter, P3, D, S, 2, Pt3, right)),
new(Ph4, philosopher('Marx', Waiter, P4, D, S, 3, Pt4, right)),
new(Ph5, philosopher('Russell', Waiter, P5, D, S, 4, Pt5, left)),
send(Waiter, init_phi, Ph1, Ph2, Ph3, Ph4, Ph5),
send_list([Ph1, Ph2, Ph3, Ph4, Ph5], start),
send(D, done_message, and(message(Waiter, free),
message(Ph1, free),
message(Ph2, free),
message(Ph3, free),
message(Ph4, free),
message(Ph5, free),
message(S, open),
message(D, destroy))),
send(D, open).
create_plate(P, N) :-
new(P, ellipse(80,80)),
X is 400 + 140 * cos(N * pi / 2.5),
Y is 400 + 140 * sin(N * pi / 2.5),
send(P, center, point(X, Y)).
create_point(N, point(X, Y)) :-
X is 400 + 220 * cos(N * pi / 2.5),
P á g i n a 12 | 24
Y is 400 + 220 * sin(N * pi / 2.5) - 20.
:- pce_begin_class(waiter , object, "gives the forks to the philosophers").
variable(f1, fork, both, "free or used").
variable(f2, fork, both, "free or used").
variable(f3, fork, both, "free or used").
variable(f4, fork, both, "free or used").
variable(f5, fork, both, "free or used").
variable(phi1, philosopher, both, "philosopher").
variable(phi2, philosopher, both, "philosopher").
variable(phi3, philosopher, both, "philosopher").
variable(phi4, philosopher, both, "philosopher").
variable(phi5, philosopher, both, "philosopher").
initialise(P, F1, F2, F3, F4, F5) :->
send(P, slot, f1, F1),
send(P, slot, f2, F2),
send(P, slot, f3, F3),
send(P, slot, f4, F4),
send(P, slot, f5, F5).
init_phi(P, Phi1,Phi2, Phi3, Phi4, Phi5) :->
send(P, slot, phi1, Phi1),
send(P, slot, phi2, Phi2),
send(P, slot, phi3, Phi3),
send(P, slot, phi4, Phi4),
send(P, slot, phi5, Phi5).
want_forks(P, Phi) :->
( get(P, slot, phi1, Phi) ,!, check_forks(P, Phi, f5, f1);
P á g i n a 13 | 24
get(P, slot, phi2, Phi),!, check_forks(P, Phi, f1, f2);
get(P, slot, phi3, Phi),!, check_forks(P, Phi, f2, f3);
get(P, slot, phi4, Phi),!, check_forks(P, Phi, f3, f4);
get(P, slot, phi5, Phi),!, check_forks(P, Phi, f4, f5)).
give_back_forks(P, Phi) :->
( get(P, slot, phi1, Phi) ,!, release_forks(P, phi1);
get(P, slot, phi2, Phi),!, release_forks(P, phi2);
get(P, slot, phi3, Phi),!, release_forks(P, phi3);
get(P, slot, phi4, Phi),!, release_forks(P, phi4);
get(P, slot, phi5, Phi),!, release_forks(P, phi5)),
get(P, slot, phi1, Phi1),
check_forks(P, Phi1, f5, f1),
get(P, slot, phi2, Phi2),
check_forks(P, Phi2, f1, f2),
get(P, slot, phi3, Phi3),
check_forks(P, Phi3, f2, f3),
get(P, slot, phi4, Phi4),
check_forks(P, Phi4, f3, f4),
get(P, slot, phi5, Phi5),
check_forks(P, Phi5, f4, f5).
release_forks(P, phi1) :-
get(P, slot, f5, F5),
send(F5, free),
get(P, slot, f1, F1),
send(F1, free).
release_forks(P, phi2) :-
get(P, slot, f1, F1),
P á g i n a 14 | 24
send(F1, free),
get(P, slot, f2, F2),
send(F2, free).
release_forks(P, phi3) :-
get(P, slot, f2, F2),
send(F2, free),
get(P, slot, f3, F3),
send(F3, free).
release_forks(P, phi4) :-
get(P, slot, f3, F3),
send(F3, free),
get(P, slot, f4, F4),
send(F4, free).
release_forks(P, phi5) :-
get(P, slot, f4, F4),
send(F4, free),
get(P, slot, f5, F5),
send(F5, free).
check_forks(P, Phi, F1, F2) :-
get(P, slot, F1, FF1),
get(P, slot, F2, FF2),
( (get(Phi, slot, status, waiting),
get(FF1, slot, status, free),
get(FF2, slot, status, free))
->
send(Phi, receive_forks),
send(FF1, used, right),
P á g i n a 15 | 24
send(FF2, used, left) ;
true).
:- pce_end_class.
:- pce_begin_class(philosopher , object, "eat, think or wait !").
variable(name, string, both).
variable(window, object, both).
variable(status, object, both, "eating/thinking/waiting").
variable(waiter, object, both).
variable(plate, object, both).
variable(mytimer, timer, both).
variable(pos, point, both).
variable(side, object, both).
variable(old_text, object, both).
variable(window_stat, object, both).
variable(line_stat, number, both).
variable(stat_wait, my_stat, both).
variable(stat_eat, my_stat, both).
variable(stat_think, my_stat, both).
% méthode appelée lors de la destruction de l'objet
% On arrête d'abord le timer pour poursuivre ensuite
% sans problème (appel par le timer de ressources libérées)
unlink(P) :->
send(P?mytimer, stop),
get(P, status, Sta),
stop_timer(P, Sta),
P á g i n a 16 | 24
get(P, slot, window_stat, WS),
get(P, slot, line_stat, LS),
get(LS, value, VLS),
get(P, slot, name, Name),
get(Name, value, V),
sformat(A, 'Statistics of philosopher : ~w', [V]),
new(Text, text(A)),
send(Text, font, font(times, bold, 16)),
Y is VLS * 30,
send(WS, display, Text, point(30, Y)),
VLS1 is VLS+1,
get(P, slot, stat_think, ST),
send(ST, statistics, WS, VLS1),
VLS2 is VLS+2,
get(P, slot, stat_eat, SE),
send(SE, statistics, WS, VLS2),
VLS3 is VLS+3,
get(P, slot, stat_wait, SW),
send(SW, statistics, WS, VLS3),
send(P, send_super, unlink).
initialise(P, Name, Waiter, Plate, Window, Window_stat, Line_stat, Point, Side) :->
% gtrace,
send(P, slot, name, Name),
send(P, slot, window, Window),
send(P, slot, window_stat, Window_stat),
Line is Line_stat * 5,
send(P, slot, line_stat, Line),
P á g i n a 17 | 24
send(P, slot, waiter,Waiter),
send(P, slot, plate,Plate),
send(P, slot, status, thinking),
send(P, slot, pos, Point),
send(P, slot, side, Side),
send(Window, display, Plate),
send(P, slot, old_text, new(_, text(' '))),
send(P, display_status),
send(P, slot, stat_wait, new(_, my_stat('Waiting'))),
send(P, slot, stat_eat, new(_, my_stat('Eating'))),
send(P, slot, stat_think, new(_, my_stat('Thinking'))).
stop_timer(P, eating) :-
get(P, slot, stat_eat, SE),
send(SE, stop).
stop_timer(P, waiting) :-
get(P, slot, stat_wait, SW),
send(SW, stop).
stop_timer(P, thinking) :-
get(P, slot, stat_think, ST),
send(ST, stop).
% internal message send by the timer
my_message(P) :->
% gtrace,
get(P, slot, status, Status),
next_status(P, Status).
% philosopher eating ==> thinking
next_status(P, eating) :-
P á g i n a 18 | 24
get(P, slot, waiter, Waiter),
get(P, slot, stat_eat, SE),
send(SE, stop),
get(P, slot, stat_think, ST),
send(ST, start),
send(Waiter, give_back_forks, P),
send(P, slot, status, thinking),
send(P, display_status),
get(P, plate, Plate),
send(Plate, fill_pattern, colour(white)),
I is random(20)+ 10,
get(P, slot, mytimer, Timer),
send(Timer, interval, I),
send(Timer, start, once).
next_status(P, thinking) :-
get(P, slot, waiter, Waiter),
send(P, slot, status, waiting),
send(P, display_status),
get(P, slot, stat_think, ST),
send(ST, stop),
get(P, slot, stat_wait, SW),
send(SW, start),
send(Waiter, want_forks, P).
% send by the waiter
% philosopher can eat !
receive_forks(P) :->
get(P, slot, stat_wait, SW),
P á g i n a 19 | 24
send(SW, stop),
get(P, slot, stat_eat, SE),
send(SE, start),
send(P, slot, status, eating),
send(P, display_status),
get(P, plate, Plate),
send(Plate, fill_pattern, colour(black)),
I is random(20)+ 5,
get(P, slot, mytimer, Timer),
send(Timer, interval, I),
send(Timer, start, once).
display_status(P) :->
get(P, old_text, OT),
free(OT),
get(P, name, Name),
get(Name, value, V),
get(P, status, Status),
choose_color(Status, Colour),
sformat(A, '~w ~w', [V, Status]),
get(P, window, W),
get(P, pos, point(X, Y)),
new(Text, text(A)),
send(Text, font, font(times, bold, 16)),
send(Text, colour, Colour),
get(Text, string, Str),
get(font(times, bold, 16), width(Str), M),
(get(P, side, right) -> X1 is X - M; X1 = X),
P á g i n a 20 | 24
send(W, display, Text, point(X1, Y)),
send(P, old_text, Text).
start(P) :->
I is random(10)+ 2,
get(P, slot, stat_think, ST),
send(ST, start),
send(P, mytimer, new(_, timer(I,message(P, my_message)))),
send(P?mytimer, start, once).
choose_color(eating, colour(blue)).
choose_color(thinking, colour(green)).
choose_color(waiting, colour(red)).
:- pce_end_class.
:- pce_begin_class(disk, ellipse, "disk with color ").
initialise(P, C, R, Col) :->
send(P, send_super, initialise, R, R),
send(P, center, C),
send(P, pen, 0),
send(P, fill_pattern, Col).
change_color(P, Col) :->
send(P, fill_pattern, Col).
:- pce_end_class.
:- pce_begin_class(my_stat , object, "statistics").
variable(name, string, both).
variable(nb, number, both).
variable(duration, real, both).
variable(start, real, both).
P á g i n a 21 | 24
initialise(P, Name) :->
send(P, name, Name),
send(P, nb, 0),
send(P, duration, 0.0).
start(P) :->
get_time(T),
send(P, slot, start, T).
stop(P) :->
get_time(Fin),
get(P, slot, nb, N),
send(N, plus,1),
send(P, slot, nb, N),
get(P, slot, duration, D),
get(P, slot, start, Deb),
get(D, value, VD),
get(Deb, value, VDeb),
X is VD + Fin - VDeb,
send(P, slot, duration, X).
statistics(P, W, L) :->
get(P, nb, N),
get(N, value, VN),
get(P, duration, D),
get(D, value, VD),
get(P, name, Name),
get(Name, value, V),
P á g i n a 22 | 24
sformat(A, '~w~tnb :~13| ~t~w~17| duration : ~t~1f~35|', [V, VN, VD]),
new(Text, text(A)),
send(Text, font, font(screen, roman, 14)),
Y is L * 30,
send(W, display, Text, point(40, Y)).
:-pce_end_class.
% forks changes of place
:- pce_begin_class(fork, line, "to help philosopphers to eat").
variable(value, number, both, "0 => 4").
variable(side, object, both, "left / right").
variable(status, object, both, "free / used").
initialise(P, Val) :->
send_super(P, initialise),
send(P, slot, value, Val),
send(P, slot, status, free),
compute(Val, free, _, PS, PE),
send(P, start, PS),
send(P, end, PE).
free(P) :->
send(P, status, free),
send(P, position).
used(P, Side) :->
send(P, status, used),
send(P, side, Side),
send(P, position).
P á g i n a 23 | 24
position(P) :->
get(P, value, V),
get(V, value, N),
get(P, status, St),
get(P, side, Side),
compute(N, St, Side, PS, PE),
send(P, start, PS),
send(P, end, PE).
compute(N, free, _Side, point(XS,YS), point(XE,YE)) :-
A is N * pi / 2.5 + pi / 5,
XS is 400 + 100 * cos(A),
YS is 400 + 100 * sin(A),
XE is 400 + 180 * cos(A),
YE is 400 + 180 * sin(A).
compute(N, used, left, point(XS,YS), point(XE,YE)) :-
A is N * pi / 2.5 + pi / 5 - 2 * pi / 15,
XS is 400 + 100 * cos(A),
YS is 400 + 100 * sin(A),
XE is 400 + 180 * cos(A),
YE is 400 + 180 * sin(A).
compute(N, used, right, point(XS,YS), point(XE,YE)) :-
A is N * pi / 2.5 + pi / 5 + 2 * pi / 15,
XS is 400 + 100 * cos(A),
YS is 400 + 100 * sin(A),
XE is 400 + 180 * cos(A),
YE is 400 + 180 * sin(A).
:- pce_end_class.
P á g i n a 24 | 24
CONCLUSIONES
El problema de la cena de los filósofos es útil para modelar procesos que compiten por
el acceso exclusivo a un número limitado de recursos, como una unidad de cinta u otro
dispositivo de E/S.
La falta de tenedores disponibles es una analogía al bloqueo de recursos compartidos
en programación real de computadores.
REFERENCIAS BIBLIOGRAFICAS
http://es.wikipedia.org/wiki/Problema_de_la_cena_de_los_fil%C3%B3sofos
http://en.wikipedia.org/wiki/Dining_philosophers_problem
http://wwwdi.ujaen.es/~lina/TemasSO/CONCURRENCIA/4ProblemasClasicosdeComun
icacionentreProcesos.htm
http://www.infor.uva.es/~cllamas/concurr/pract97/immartin/
http://lsi.vc.ehu.es/pablogn/docencia/manuales/SO/TemasSOuJaen/CONCURRENCIA/
4ProblemasClasicosdeComunicacionentreProcesos.htm
http://www.labc.usb.ve/paginas/jregidor/EC3731/pdfs/TareaInterbloqueoSolucion.pdf