Next: About this document Up: Spooler de impresora Previous: Spooler de impresora

## Spooler de impresora (SOLUCIÓN)

#### Grafo de Procesos

#### Especificación de los procesos

    TASK Cliente;
    (*   ^^^^^^^                                                              *)
    VAR
         trabajo : Trabajos;
    BEGIN
         LOOP
              << Determinar que imprimir -> trabajo >>;
              DOBLE_SPOOL.Imprimir(trabajo);
         END (* loop *)
    END ReconocedorOrdenes;

    TASK Servidor;
    (*   ^^^^^^^^                                                             *)
    VAR
         trabajo : Trabajos;
    BEGIN
         LOOP
              DOBLE_SPOOL.ConseguirTrabajo(trabajo);
              << Imprimir trabajo >>
         END (* loop *);
    END Editor;

donde las operaciones `Imprimir` y `ConseguirTrabajo` del modulo `DOBLE_SPOOL` se codifican:

    PROCEDURE Imprimir(trabajo:Trabajo);
    (*        ^^^^^^^^                                                         *)
    VAR
         alSecundario : BOOLEAN;
    BEGIN
         CONTROL_SPOOL.InicioGrabar(trabajo,alSecundario);
         IF alSecundario THEN
            SECUNDARIO.Grabar(trabajo);
            CONTROL_SPOOL.FinGrabarSec;
         END (* if *)
    END Imprimir;

    PROCEDURE ConseguirTrabajo(VAR trabajo : Trabajo);
    (*        ^^^^^^^^^^^^^^^^                                                 *)
    VAR
         enSecundario : BOOLEAN;
    BEGIN
         CONTROL_SPOOL.InicioLeer(trabajo,enSecundario);
         IF enSecundario THEN
            SECUNDARIO.Leer(trabajo);
            CONTROL_SPOOL.FinLeerSec;
         END (* if *)
    END ConseguiTrabajo;

El estado del monitor `CONTROL_SPOOL` lo definen las siguientes variables del mismo:

    TYPE
      Buffers = (pri,sec);

    VAR
      apuntes  : << Cola (FIFO) con elementos del tipo Buffers >>;
                 (* Su objetivo es determinar en que buffer esta *)
                 (* almacenado el siguiente trabajo              *)
      primario : << Cola (FIFO) con elementos del tipo Trabajo >>;
      ocupadoSec : BOOLEAN; (* determina si el buffer secundario, fuera *)
                            (* del monitor esta siendo utilizado        *)

A continuación se exponen las tablas de bloqueo del monitor `CONTROL_SPOOL`.

#### Tabla de Bloqueos

#### Tabla de Desbloqueos

Las tablas de bloqueo y desbloque del monitor `SECUNDARIO` no se especifican dado que son las tablas de bloqueo conocidas para un monitor cuyo recurso es un buffer.

El código de las operaciones del monitor `CONTROL_SPOOL` se detalla a continuación. La inclusión de las propiedades de vivacidad ha obligado a introducir una variable `esperaLeer` que determina si el servidor espera leer y si esto no ocurre se puede liberar a los procesos que quieran grabar. De nuevo no detallamos el monitor secundario dada su simplicidad.

    <M W>
    MODULE SPOOLER;
    (*
    ****************************************************************************
    * Module           : SPOOLER
    * Subject          : Programa CC-modula que implementa un spooler con
    *                    doble buffering
    * Authors          :
    * Created on       :
    * Last modified by :
    * Last modified on :
    * Status           : OK
    *)
    ...
    MODULE DOBLE_SPOOL;
    (*
    ****************************************************************************
    * Module           : DOBLE_SPOOL (Local Module)
    * Subject          : Modulo local que se encarga de encapsular los
    *                    monitores y en el que se definen los procedimientos
    *                    Imprimir y ConseguirTrabajo
    *)

    MONITOR CONTROL_SPOOL;
    (*
    ****************************************************************************
    * Module           : CONTROL_SPOOL (Monitor)
    * Subject          : Monitor que controla el acceso a los buffers
    *)

    IMPORT ...

    PUBLIC InicioGrabar, FinGrabarSec, InicioLeer, FinLeerSec;

    VAR
    (*  Recurso:                                                               *)
        << Las anteriores + >>
        esperaLeer : BOOLEAN;
    (*  Colas de espera:                                                       *)
         permisoGrabar : CONDITION;
         permisoLeer   : CONDITION;
         permisoVisualizar : CONDITION;

    PROCEDURE InicioGrabar (trabajo : Trabajo; VAR alSecundario : BOOLEAN);
    (*        ^^^^^^^^^^^^                                                     *)
    BEGIN
         IF Lleno(primario) AND ocupadoSec THEN
              Delay(permisoGrabar);
         END (* if *);
                                             (*  PRE: secundario libre o       *)
                                             (*       primario no lleno        *)
    (*  Operacion                                                              *)
         IF ocupadoSec THEN
            Insertar(primario,trabajo);
            alSecundario := FALSE;
            Insert(apuntes,prim);
         ELSE
            ocupadoSec := TRUE;
            alSecundario := TRUE;
            Insert(apuntes,sec);
         END (* if *)
                                             (*  POS: no vacio primario        *)
         IF Primero(apuntes)=prim THEN
              Continue(permisoLeer);
         END (* if *);
    END InicioGrabar;

    PROCEDURE InicioLeer (VAR orden : Orden; VAR enSecundario : BOOLEAN);
    (*        ^^^^^^^^^^                                                       *)
    VAR
         acceso : Buffers;
    BEGIN
         IF Vacia(apuntes) OR (* evaluacion "perezosa" del OR *)
            Primero(apuntes)=sec AND ocupadoSec THEN
              esperaLeer := TRUE;
              Delay(permisoActualizar);
              esperaLeer := FALSE
         END (* if *);
                                             (*  PRE: hay trabajos y o el      *)
                                             (*       primero esta en el       *)
                                             (*       primario o el secundario *)
                                             (*       esta libre               *)
    (*  Operacion                                                              *)
         Extract(apuntes,acceso);
         IF acceso=prim THEN
            Extraer(primario,trabajo);
            enSecundario := FALSE;
         ELSE
            ocupadoSec := TRUE;
            enSecundario := TRUE;
         END (* if *);
                                             (*  POS: primario no lleno o      *)
                                             (*       secundario ocupado       *)
         IF NOT ocupadoSec THEN
            Continue(permisoGrabar);
         END (* if *)
    END InicioLeer;

    PROCEDURE FinLeerSec;
    (*        ^^^^^^^^^^                                                       *)
    BEGIN
    (*  Operacion                                                              *)
         ocupadoSec := FALSE;
                                             (*  POS: secundario libre         *)
         Continue(permisoGrabar);
    END FinLeerSec;

    PROCEDURE FinGrabarSec;
    (*        ^^^^^^^^^^^^                                                     *)
    BEGIN
    (*  Operacion                                                              *)
         ocupadoSec := FALSE;
                                             (*  POS: secundario libre y       *)
                                             (*       hay trabajos             *)
         IF esperaLeer THEN
            Continue(permisoLeer);
         ELSE
            Continue(permisoGrabar);
         END (* if *)
    END FinGrabarSec;

    BEGIN
      ocupadoSec := FALSE;
      << Iniciar a vacias apuntes y primario >>;
      esperaLeer := FALSE;
    END MONITOR;
    (*************************************)

    MONITOR SECUNDARIO;
    (*
    ****************************************************************************
    * Module           : SECUNDARIO (Monitor)
    * Subject          : Buffer lento en disco
    *)

    IMPORT ...

    PUBLIC Grabar, Leer;
    ...
    END MONITOR;
    (*************************************)
    ...
    END DOBLE_SPOOL;
    (*************************************)
    ...
    (************** PROGRAMA PRINCIPAL ****************)
    BEGIN
         COBEGIN
              FORALL j:=1 TO N DO
                     Cliente;
              END (* forall *);
              Servidor;
         COEND;
    END SPOOLER.