next up previous
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.


Angel Herranz Nieva
Thu Oct 31 20:12:45 MET 1996