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.
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.