Como una variante de la familia de problemas basados en un protocolo de acceso (del que es su más conocido respresentante el problema de los Lectores y los Escritores), el restaurante de Los Corazones Solitarios expresa de nuevo la necesidad de gestionar convenientemente el acceso a un recurso (salones en el caso del restaurante) por parte de unos procesos, cuyo acceso "indiscriminado" sería desastroso (peleas, pérdida de clientes, etc..). En este caso, la incompatibilidad entre procesos se da porque hay clientes que fuman y otros que no fuman, y se quiere impedir que puedan encontrarse juntos en un salón del restaurante.
Si el enunciado hubiera planteado que el restaurante tiene un único salón, el problema se hubiera reducido al conocido del El puente sobre el río, en el cual los coches que vienen en un sentido no deben encontrarse, obviamente, con los que vienen por el otro. En este problema, por contra, se plantea la existencia de 3 salones con lo que la gestión parece complicarse algo más.
La primera cuestión es razonar sobre el siguiente pregunta: cuántos monitores son necesarios para realizar la anterior gestión?. La respuesta debe ser uno únicamente. La razón es que en determinados momentos de la ejecución se debe conocer el estado global del restaurante. Si la gestión del estado de los salones la repartiéramos entre 3 monitores (uno en cada monitor), no habría ninguna forma segura de saber cual es el estado global del restaurante.
El resto de consideraciones no es más que seguir las condiciones de ejecución expresadas en el enunciado y utilizarlas aplicando la metodología de programación basada en monitores conocida: estudiar primero las condiciones de seguridad, y luego más tarde las de prioridad/viveza. Para las condiciones de sincronización se han utilizado dos funciones:
MODULE CorazonesSolitarios; CONST NumFumadores = 10; NumNoFumadores = 10; TYPE TipoSalon = [1..3]; TipoCliente = (ninguno, fumador, nofumador); VAR I : CARDINAL; (* Replicador *) MONITOR Maitre; IMPORT TipoSalon, TipoCliente; PUBLIC EntradaCliente, SalidaCliente; CONST NumMesas = 8; TYPE EstadoSalon = RECORD clienteActual : TipoCliente; mesasOcupadas : CARDINAL END; VAR I : TipoSalon; clienteEspera : ARRAY [fumador..nofumador] OF CONDITION; salones : ARRAY TipoSalon OF EstadoSalon; PROCEDURE MesaLibre (cliente: TipoCliente (* In *)) : BOOLEAN; BEGIN << .... >> END MesaLibre; PROCEDURE ElegirSalon (cliente : TipoCliente (* In *)) : TipoSalon; BEGIN << .... >> END ElegirSalon; PROCEDURE EntradaCliente (VAR salon : TipoSalon (* Out *), cliente : TipoCliente (* In *)); BEGIN IF NOT MesaLibre (cliente) THEN Delay (clienteEsperando [cliente]); END; (* IF *) salon := ElegirSalon (cliente); WITH salones [salon] DO INC (mesasOcupadas); clienteActual := cliente; END; (* WITH *) IF MesaLibre (cliente) THEN Continue (clienteEsperando [cliente]) END (* IF *) END EntradaCliente; PROCEDURE SalidaCliente (cliente : TipoCliente (* In *); salon : TipoSalon (* In *)); BEGIN WITH salones [salon] DO DEC (mesasOcupadas); IF mesasOcupadas = 0 THEN clienteActual := ninguno END; (* IF *) IF clienteActual = ninguno THEN Continue (clienteEsperando [OtroCliente(cliente)]) ELSE Continue (clienteEsperando cliente) END (* IF *) END (* CASE *) END SalidaCliente; BEGIN (* MONITOR *) FOR I:=1 TO 3 DO WITH salones [I] DO clienteActual := ninguno; mesasOcupadas := 0; END (* WITH *) END (* FOR *) END MONITOR; TASK Cliente (cliente : TipoCliente; ident : CARDINAL ); VAR salon : TipoSalon; BEGIN LOOP Maitre.EntradaCliente (cliente, salon); << Comer >> Maitre.Salida (cliente, salon); END Cliente; BEGIN COBEGIN FORALL I:=1 TO NumFumadores DO Cliente (I, fumador); END; (* FORALL *) FORALL I:=1 TO NumNoFumadores DO Cliente (I, nofumador); END; (* FORALL *) COEND END CorazonesSolitarios.