Next: El peluquero dormilón Up: Manejadores y servidores Previous: Manejadores y servidores

## Manejadores y servidores de disco (SOLUCIÓN)

En este problema se propone buscar una solución que gestione las operaciones, tanto de lectura como de escritura, que realizan unos usuarios sobre la información almacenada en varios discos independientes. Como se proponía en el gráfico del enunciado, cada disco va a tener asociados: un proceso Manejador (manipulador directo) del disco y un proceso Servidor que atiende y gestiona todas las peticiones que se hagan sobre él. Todos los discos son similares, y se diferencian porque cada uno tiene un identificador diferente. Por tanto, la solución del problema sólo requiere la implementación de tres tipos de tareas: Manejador, Servidor y Cliente.

1. Grafo de procesos.

2. Descripción de los procesos Manejador y Servidor.

   Obsérvese la función que desempeñan las operaciones de las colas de peticiones, en la implementación de la sincronización en el proceso servidor. Por otro lado, resulta relevante el hecho de que el proceso manejador desempeñe una actitud activa en la ejecución, no teniendo que esperar a que exista una petición de operación del Servidor, sino adelantándose a ésta e indicando su situación de ``preparado'' para operar sobre el disco.

       MODULE  Discos;
       FROM COLAS IMPORT TipoCola,  (* TipoPeticion *)
                         CreaVacia,
                         Llena,
                         Vacia,
                         Insertar,
                         Borrar,
                         Primero;

       CONST  NumDiscos = 3;
              NumClientes = 5;

       TYPE  TipoDato = INTEGER;

       TYPE  TipoPeticion = RECORD
                              sector: INTEGER;
                              CASE  esLectura: BOOLEAN  OF
                                TRUE:  cliente: INTEGER |
                                FALSE: dato: TipoDato
                              END
                            END;

       TYPE  RespuestaLectura = RECORD
                                  dato: TipoDato;
                                  cliente: INTEGER
                                END;

       VAR  datoLeido: ARRAY [1..NumClientes] OF CHANNEL;   (* cliente *)

       VAR  pedirOperacion,
            pedirOrden,
            retornoLectura,     (* servidor *)
            orden:                                          (* disco *)
            ARRAY [1..NumDiscos] OF CHANNEL;

       TASK  Manejador (i: INTEGER);
         VAR  peticion: TipoPeticion;
              respuesta: RespuestaLectura;
       BEGIN
         (*... iniciar disco ...*)
         LOOP
           Send(pedirOrden[i], TRUE);
           Receive(orden[i], peticion);
           IF  peticion.esLectura  THEN
             (*... Leer 'respuesta.dato' del sector 'peticion.sector' ...*)
             respuesta.cliente := peticion.cliente;
             Send(retornoLectura[i], respuesta)
           ELSE
             (*... Escribir 'peticion.dato' en 'peticion.sector' ...*)
           END
         END
       END Manejador;

       TASK  Servidor(i: INTEGER);
         VAR  cola:  TipoCola;
              x: BOOLEAN;
              peticion: TipoPeticion;
              respuesta: RespuestaLectura;
       BEGIN
         GetChannel(pedirOperacion[i]);
         GetChannel(pedirOrden[i]);
         GetChannel(retornoLectura);
         CrearVacia (cola);
         LOOP
           SELECT
             WHEN  NOT Llena(cola), Receive(pedirOperacion[i], peticion)  DO
               Insertar(cola, peticion)
             WHEN  NOT Vacia(cola), Receive(pedirOrden[i], x) DO
               Primero (cola, peticion);
               Borrar (cola);
               Send(orden[i], peticion)
             WHEN  TRUE, Receive(retornoLectura[i], respuesta)  DO
               Send(datoLeido[respuesta.cliente], respuesta.dato)
           END
         END
       END Servidor;

3. Descripción de los procesos clientes.

   La actividad de los clientes está sujeta a la ejecución de una de las dos operaciones (Leer o Escribir) para actuar sobre el disco. Dichas operaciones son, precisamente, los ``servicios'' que ofrece cada servidor de disco a los clientes. Junto a todo esto, la implementación de las operaciones debe hacerse bajo la forma de procedimientos con unas cabeceras determinadas.

   Las operaciones de lectura y escritura son diferentes en cuanto que lo es el sentido de la comunicación que producen. Así, mientras que la operación de escritura no implica la espera del proceso cliente (una vez se haya notificado al servidor la petición no hay que esperar a que se escriba realmente), para el caso de la lectura esto no es así, y el proceso cliente debe esperar a recibir los datos que haya solicitado. Lo anterior tiene una trascendencia mayor que la esperada para el caso de las lecturas:

   > ... para que los datos puedan ser remitidos desde el servidor al cliente, éste previamente debe haberle indicado cuál es el canal por el que deberá enviarle dichos datos.

   Como el enunciado obligaba a la utilización de unas cabeceras de procedimientos en las cuales no se hace ninguna mención al canal de recepción, la solución pasa por incluir, cuando la operación es de lectura, el canal de recepción dentro del mensaje enviado al servidor.

       TASK  Cliente(i: INTEGER);
       VAR
           disco,
           sector : CARDINAL;
           dato   : TipoDato;

         PROCEDURE  Leer(disco, sector: INTEGER; VAR dato: TipoDato);
           VAR  lectura: PeticionLectura;
         BEGIN
           lectura.sector := sector;
           lectura.cliente := i;
           Send(pedirLectura[disco], lectura);
           Receive(datoLeido[i], dato)
         END Leer;

         PROCEDURE  Escribir(disco, sector: INTEGER; dato: TipoDato);
           VAR  escritura: PeticionEscritura;
         BEGIN
           escritura.sector := sector;
           escritura.dato := dato;
           Send(pedirEscritura[disco], escritura)
         END Escribir;

       BEGIN
         GetChannel(datoLeido[i]);
         LOOP
            (* .. Operaciones de lectura y/o escritura .. *)
         END
       END Cliente;

       VAR  k: INTEGER;

       BEGIN
         COBEGIN
           FORALL k := 1 TO NumDiscos  DO
             Manejador(k);
             Servidor(k)
           END;
           FORALL k := 1 TO NumClientes  DO
             Cliente(k)
           END;
         COEND
       END Discos.

Next: El peluquero dormilón Up: Manejadores y servidores Previous: Manejadores y servidores