Next: Almacén automatizado Up: El restaurante ``Los Previous: El restaurante ``Los

## El restaurante ``Los corazones solitarios'' (SOLUCIÓN)

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:

- MesaLibre que permite averiguar si hay una mesa libre para el tipo de cliente que lo solicita, atendiendo a las condiciones de sincronización,

- ElegirSalon que devuelve, una vez que se sabe que hay una mesa libre para el cliente, el salón a que debe dirigirse.

    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.

Next: Almacén automatizado Up: El restaurante ``Los Previous: El restaurante ``Los