El problema del peluquero dormilón (originalmente, el barbero dormilón) es un clásico de la Programación Concurrente. En él se propone la discusión sobre cómo gestionar el ``transito'' por una pequeña peluquería (recurso compartido), por parte de dos tipos de procesos: el peluquero y los clientes. El enunciado sugiere que durante la ejecución la interacción entre el peluquero y un cliente se puede producir muy a menudo y que, por tanto, deben establecerse los mecanismos de sincronización adecuados para evitar que los dos ``colisionen'' dentro la peluquería; es decir, asegurar uno sólo es el que se mueve en cada momento.
MODULE PeluqueroDormilon; CONST NumClientes = 6; VAR I : [1..NumClientes]; TASK Peluquero; BEGIN LOOP << Esperar al próximo cliente. Si no hay ninguno dormir >> << Cortar el pelo. >> << Abrir la puerta y esperar a que salga el cliente >> END (* LOOP *) END Peluquero; TASK Cliente; BEGIN << Pregunto si hay sitio en la peluquería >> IF NOT << Hay sitio >> THEN << Me largo a otra peluquería >> ELSE << Espero a que me toque >> << Me siento en el sillón y me cortan el pelo >> << Me voy de la peluquería >> END (* IF *) END Cliente; BEGIN COBEGIN Peluquero; FORALL I:= 1 TO NumClientes DO Cliente END; (* FORALL *) COEND END PeluqueroDormilon.
MODULE PeluqueroDormilon; ......................... MONITOR Peluqueria; PUBLIC EsperarCliente, PedirCorteDePelo, FinalCorteDePelo, AbrirPuertaEsperarSalida, ClienteSale; PROCEDURE EsperarCliente; BEGIN IF << alg£n cliente espera >> THEN << atender cliente >> ELSE << dormir >> END (* IF *) END EsperarCliente; PROCEDURE PedirCorteDePelo (VAR meAtienden : BOOLEAN); BEGIN meAtienden := TRUE; IF << No hay sitio en la peluquería >> AND NOT << Peluquero dormido >> THEN meAtienden := FALSE ELSIF << Peluquero dormido >> THEN << Despertar al peluquero >> ELSE << Esperar en una de las sillas libres >> END (* IF *) END PedirCorteDePelo; PROCEDURE FinalCorteDePelo; BEGIN << Esperar a que el peluquero termine y abra la puerta >> END FinalCorteDePelo; PROCEDURE ClienteSale; BEGIN << Avisar al peluquero de que el cliente ha salido >> END ClienteSale; PROCEDURE AbrirPuertaEsperarSalida; BEGIN << El peluquero ha abierto la puerta y avisa al cliente >> << Esperar a que salga el cliente >> END AbrirPuertasEsperarSalida; END MONITOR; TASK Peluquero; BEGIN LOOP Peluqueria.EsperarCliente; (* ... Cortar el pelo ... *) Peluqueria.AbrirPuertaEsperarSalida; END (* LOOP *) END Peluquero; TASK Cliente; VAR haySitio : BOOLEAN; BEGIN (* .. Pregunto si me va a poder atender el peluquero .. *) Peluqueria.PedirCorteDePelo (haySitio); IF NOT haySitio THEN (* .. Me largo a otra peluquería .. *) ELSE (* .. Me siento y espero a que me corten el pelo .. *) Peluqueria.FinalCorteDePelo; (* .. Me voy de la peluquería .. *) Peluqueria.ClienteSale END END Cliente; BEGIN ........ END PeluqueroDormilon.
PROCEDURE EsperarCliente; BEGIN IF sillasLibres = NumSillas THEN dormido := TRUE; Delay (siesta); dormido := FALSE ELSE Continue (clienteEsperando) END (* IF *) END EsperarCliente; PROCEDURE PedirCorteDePelo (VAR meAtienden : BOOLEAN); BEGIN meAtienden := TRUE; IF (sillasLibres = 0) AND NOT dormido THEN meAtienden := FALSE ELSIF dormido THEN Continue (siesta) ELSE DEC (sillasLibres); Delay (clienteEsperando); INC (sillasLibres); END; (* IF *) END PedirCorteDePelo; PROCEDURE FinalCorteDePelo; BEGIN Delay (puertaAbierta); END FinalCorteDePelo; PROCEDURE ClienteSale; BEGIN Continue (salidaCliente); END ClienteSale; PROCEDURE AbrirPuertaEsperarSalida; BEGIN Continue (puertaAbierta); Delay (salidaCliente) END AbrirPuertaEsperarSalida; BEGIN (* MONITOR *) dormido := TRUE; sillasLibres := NumSillas END MONITOR;
< M W > MODULE PeluqueroDormilon; CONST NumClientes = << .. >>; MONITOR Peluqueria; PUBLIC SiguienteCliente, PedirCorteDePelo, FinalCorteDePelo, AbrirPuerta, CerrarPuerta, ClienteSale; CONST NumSillas = << .. >>; VAR clienteEsperando : CONDITION; siesta : CONDITION; puertaAbierta : CONDITION; salidaCliente : CONDITION; dormido : BOOLEAN; sillasLibres : CARDINAL; hayCliente : BOOLEAN; PROCEDURE SiguienteCliente; BEGIN IF sillasLibres = NumSillas THEN dormido := TRUE; Delay (siesta); dormido := FALSE ELSE Continue (clienteEsperando) END (* IF *) END SiguienteCliente; PROCEDURE PedirCorteDePelo (VAR meAtienden : BOOLEAN); BEGIN meAtienden := TRUE; IF sillasLibres = 0 THEN meAtienden := FALSE ELSIF dormido THEN hayCliente := TRUE; Continue (siesta) ELSE DEC (sillasLibres); Delay (clienteEsperando); INC (sillasLibres); hayCliente := TRUE END; (* IF *) END PedirCorteDePelo; PROCEDURE FinalCorteDePelo; BEGIN Delay (puertaAbierta); END FinalCorteDePelo; PROCEDURE ClienteSale; BEGIN hayCliente := FALSE; Continue (salidaCliente); END ClienteSale; PROCEDURE AbrirPuerta; BEGIN Continue (puertaAbierta); END AbrirPuerta; PROCEDURE CerrarPuerta; BEGIN IF hayCliente THEN Delay (salidaCliente); END (* IF *) END CerrarPuerta; BEGIN (* MONITOR *) dormido := TRUE; hayCliente := FALSE; sillasLibres := NumSillas END MONITOR; TASK Peluquero; BEGIN LOOP Peluqueria.EsperarCliente; (* ... Cortar el pelo ... *) Peluqueria.AbrirPuerta; (* ... Despedir al cliente .. *) Peluqueria.CerrarPuerta END (* LOOP *) END Peluquero; TASK Cliente; VAR haySitio : BOOLEAN; BEGIN (* .. Pregunto si me va a poder atender el peluquero .. *) Peluqueria.PedirCorteDePelo (haySitio); IF NOT haySitio THEN (* .. Me largo a otra peluquería .. *) ELSE (* .. Me siento en el sillon y espero a que me corten el pelo .. *) Peluqueria.FinalCorteDePelo; (* .. Me voy de la peluqueria .. *) Peluqueria.ClienteSale END END Cliente; VAR I : [1..NumClientes]; BEGIN COBEGIN Peluquero; FORALL I:= 1 TO NumClientes DO Cliente END; (* FORALL *) COEND END PeluqueroDormilon.