22.11.2014 Views

Tema 3: MONITORES - Departamento de Lenguajes y Sistemas ...

Tema 3: MONITORES - Departamento de Lenguajes y Sistemas ...

Tema 3: MONITORES - Departamento de Lenguajes y Sistemas ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Tema</strong> 3. Monitores<br />

Programación Concurrente<br />

Depto. <strong>de</strong> <strong>Lenguajes</strong> y <strong>Sistemas</strong> Informáticos<br />

Universidad <strong>de</strong> Granada


Contenidos<br />

1. Concepto <strong>de</strong> Monitor<br />

1.1. Fundamento teórico <strong>de</strong> los monitores<br />

1.2. Sintaxis <strong>de</strong> los monitores<br />

1.3. Exclusión mutua con monitores<br />

1.4. Instanciación <strong>de</strong> monitores<br />

2. Sincronización en Monitores<br />

2.1. Primitivas <strong>de</strong> sincronización en monitores<br />

2.2. Efecto <strong>de</strong> las operaciones sincronización sobre la exclusión<br />

mutua <strong>de</strong>l monitor<br />

2.3. Equivalencia entre semáforos y monitores<br />

2.4. Problemas paradigmáticos resueltos con monitores


1. Concepto <strong>de</strong> Monitor<br />

1.1. Fundamento teórico <strong>de</strong> los monitores<br />

• Inconvenientes mecanismos como los semáforos:<br />

– Basados en variables globales → No modular.<br />

– Uso y función <strong>de</strong> las variables no explícito.<br />

– Operaciones sobre variables recurso dispersas y no protegidas.<br />

• No Acceso estructurado ni encapsulación → Fuente <strong>de</strong> errores.<br />

• Monitor (Hoare 1974) : Mecanismo <strong>de</strong> alto nivel que permite<br />

– Definir objetos abstractos compartidos (una colección <strong>de</strong> datos y procedimientos<br />

asociados que se comparten por varios procesos).<br />

– Garantizar acceso exclusivo a datos e implementar sincronización.<br />

• Monitor = Encapsulación<br />

– Definición recurso (datos).<br />

– Operaciones <strong>de</strong> Manipulación (procedims.)<br />

• Recurso: Se percibe como un módulo al que se acce<strong>de</strong> concurrentemente.<br />

– El usuario ignora <strong>de</strong>talles <strong>de</strong> implementación <strong>de</strong>l recurso y <strong>de</strong> las<br />

operaciones asociadas.


1. Concepto <strong>de</strong> Monitor<br />

1.1.1. Centralización <strong>de</strong> funciones críticas.<br />

• Origen: S.O. concurrente → Monitor monolítico → Programa que centraliza las<br />

funciones críticas (asig./planif. recursos) <strong>de</strong>l sistema.<br />

• Soportados por facilida<strong>de</strong>s hardware:<br />

– Ejecución en modo ininterrumpido (E.M.).<br />

– Acceso a posiciones <strong>de</strong> memoria privilegiadas.<br />

– Ejecución <strong>de</strong> instrucciones privilegiadas.<br />

• Monitor: Versión “<strong>de</strong>scentralizada” <strong>de</strong>l monitor original.<br />

• Cada monitor tiene:<br />

– Una función específica.<br />

– Datos e instrucciones propias.<br />

• Ejemplo:<br />

– M1 : único monitor que acce<strong>de</strong> a v1 → asegura E.M. ya que será<br />

ininterrumpible (la entrada al monitor <strong>de</strong> un proceso excluye la entrada <strong>de</strong><br />

otros).<br />

– Único procesamiento sobre v1 programado en M1.<br />

• Diferentes monitores (o instancias <strong>de</strong> un monitor) para diferentes tareas.<br />

– Mayor Eficiencia (+ Concurrencia)<br />

– Mayor Robustez: Modularidad


1. Concepto <strong>de</strong> Monitor<br />

1.1.2. Estructuración en el acceso a los datos.<br />

• Definición tipos para las operaciones y los datos (T.A.D.).<br />

• Paradigma <strong>de</strong> Programación Modular:<br />

– Módulo: Conjunto <strong>de</strong> procedimientos relacionados + datos.<br />

– Principio <strong>de</strong> Ocultación <strong>de</strong> datos: Hacer local al módulo todo lo<br />

que no <strong>de</strong>be ser visible.<br />

• Ejemplo: Módulo <strong>de</strong> pila. Resolver:<br />

– Interfaz <strong>de</strong> usuario: procedimientos push y pop.<br />

– Representación (p.e. array) sólo accedida mediante interfaz.<br />

– Inicialización antes <strong>de</strong> uso.<br />

• <strong>Lenguajes</strong> <strong>de</strong> Programación Dirigida a Objetos → Clase.


1. Concepto <strong>de</strong> Monitor<br />

1.2. Sintaxis <strong>de</strong> los monitores<br />

Estructura <strong>de</strong> un monitor <strong>de</strong> nombre name y procedimientos<br />

op1,...,opN:<br />

Monitor name;<br />

var<br />

... Declaración <strong>de</strong> variables permanentes<br />

procedure op1 (...);<br />

var<br />

... Declaración <strong>de</strong> variables locales a op1<br />

{ ... Código que implementa op1 }<br />

... ... ...<br />

procedure opN (...);<br />

var<br />

... Declaración <strong>de</strong> variables locales a opN<br />

{ ... Código que implementa opN }<br />

begin<br />

end.<br />

... Código para inicializar variables permanentes


1. Concepto <strong>de</strong> Monitor<br />

1.2.1. Protección <strong>de</strong> los datos en el monitor.<br />

• Ámbito variables permanentes <strong>de</strong>l monitor : Código monitor<br />

(procedimientos y cod. inicialización).<br />

• Acceso variables permanentes: sólo <strong>de</strong>ntro <strong>de</strong> los<br />

procedimientos.<br />

• Procedimientos sólo acce<strong>de</strong>n:<br />

– Variables permanentes<br />

– Variables locales<br />

• Valores variables permanentes se mantienen entre diferentes<br />

ejecuciones <strong>de</strong> los procedimientos.<br />

• Comunicación monitor-mundo exterior: A través <strong>de</strong> los<br />

parámetros <strong>de</strong> los procedimientos.


1. Concepto <strong>de</strong> Monitor<br />

1.2.2. Procedimientos <strong>de</strong>l Monitor.<br />

• Comunes a todos los procesos <strong>de</strong>l sistema.<br />

• Nueva llamada proced. → Nuevos valores parámetros y<br />

variables locales.<br />

• Sintaxis:<br />

nombremonitor.nombreprocedimiento(parámetros_reales);<br />

1.2.3. Código <strong>de</strong> inicialización<br />

• Ejecución sólo 1 vez: Inicializa vars. Permanentes.<br />

• Tras Ejecución: Monitor = objeto pasivo (datos + proceds.)<br />

• Única forma ejecutar monitor: llamar proced.


1. Concepto <strong>de</strong> Monitor<br />

1.3. Exclusión mútua con monitores<br />

• Acceso al monitor en E.M.<br />

– Sólo un proceso en un momento dado pue<strong>de</strong> ejecutar un procedimiento<br />

• Subsiguientes llamadas esperan finalización.<br />

– Violación podría tener efectos caóticos sobre vars.<br />

• Ventajas sobre Semáforos (soluc. no estructurada):<br />

– Protección Variables: evita interferencias exteriores<br />

– Estructuración acceso: Espera y señalización se programan <strong>de</strong>ntro monitor. Si<br />

el monitor es correcto, lo será cada instancia utilizada por los procesos.<br />

– E.M. garantizada automáticamente → No errores.<br />

• Invariante: Define una relación sobre los datos <strong>de</strong>l monitor.<br />

– Se mantiene siempre excepto cuando un procedimiento está ejecutándose.<br />

– Se ha <strong>de</strong> cumplir antes <strong>de</strong> entrar y <strong>de</strong>spués <strong>de</strong> salir.<br />

– Se ha <strong>de</strong> reestablecer el invariante en procedimientos antes <strong>de</strong> <strong>de</strong>volver el<br />

control o suspen<strong>de</strong>r el proceso.


1. Concepto <strong>de</strong> Monitor<br />

1.4. Instanciación <strong>de</strong> monitores<br />

• Permite <strong>de</strong>clarar diversos monitores con estructura y<br />

comportamiento idénticos (Ej.: planificar varios recursos<br />

similares).<br />

• Declaración tipo monitor:<br />

Class Monitor nombre_clase<br />

.... .......<br />

• Instanciación <strong>de</strong> monitores: monitor1, monitor2: nombreclase;<br />

• Práctica: se permite <strong>de</strong>clarar varias instancias e incluso<br />

conjuntos parametrizados <strong>de</strong> monitores.<br />

• Implementación con procedimientos reentrantes:<br />

– Basta asignar nuevas instancias <strong>de</strong> las variables globales<br />

para cada instancia <strong>de</strong> un monitor.


2. Sincronización en Monitores<br />

2.1. Primitivas <strong>de</strong> sincronización en monitores<br />

• Sincronización: Facilidad <strong>de</strong> bloqueo-activación <strong>de</strong> acuerdo<br />

a una condición.<br />

• Propósitos <strong>de</strong> las instrucciones <strong>de</strong> sincronización en<br />

semáforos:<br />

– Bloqueo-activación<br />

– Cuenta (representación condición)<br />

• En monitores:<br />

– Sólo Bloqueo-activación<br />

– Representación condición mediante datos protegidos <strong>de</strong>l<br />

monitor


2. Sincronización en Monitores<br />

2.1. Primitivas <strong>de</strong> sincronización en monitores (cont.)<br />

• Ejemplo <strong>de</strong> monitor: Planificador <strong>de</strong> un único recurso (sem. binario)<br />

monitor recurso;<br />

var ocupado: boolean;<br />

noocupado: condicion;<br />

procedure adquirir;<br />

{if ocupado then noocupado.wait; ocupado := true}<br />

procedure liberar;<br />

{ocupado := false; noocupado.signal;}<br />

begin<br />

ocupado := false /* valor inicial*/<br />

end;


2. Sincronización en Monitores<br />

2.1.1. Semántica <strong>de</strong> las operaciones<br />

●<br />

Wait: "estoy esperando a que algo (condición) ocurra".<br />

– Bloquea proceso.<br />

●<br />

Signal: "estoy señalando que algo (condición) ha ocurrido".<br />

– Reactiva un proceso bloqueado en esa condición.<br />

• Responsabilidad <strong>de</strong>l programador→ que el proceso ejecute:<br />

– Wait: cuando algo (condición) no se dé<br />

– Signal: Cuando la condición acabe <strong>de</strong> activarse.


2. Sincronización en Monitores<br />

2.1.2. Variables <strong>de</strong> condición o señales<br />

• Más <strong>de</strong> una razón para esperar:<br />

– representan distintas condiciones<br />

– Deben <strong>de</strong> ser diferenciadas por wait y signal.<br />

• Nuevo tipo <strong>de</strong> variable:<br />

– Variable <strong>de</strong> condición o señal. Sin valor almacenado (ni V, ni F).<br />

– Una variable condición por cada razón <strong>de</strong> bloqueo.<br />

• Operaciones<br />

Nombre_variable_condición.wait<br />

Nombre_variable_condición.signal<br />

• Representación variable condición<br />

– Cola (inicialmente vacía) <strong>de</strong> procs esperando en condición. Invisible<br />

a procs.<br />

• Más <strong>de</strong> un proceso pue<strong>de</strong> estar <strong>de</strong>ntro <strong>de</strong>l mismo monitor, aunque sólo<br />

uno ejecutándose (resto bloqueados en variables condición).


2. Sincronización en Monitores<br />

2.1.3. Propiedad FIFO <strong>de</strong> las colas <strong>de</strong> condición<br />

• Más <strong>de</strong> un proc. esperando en condición →<br />

– condición.signal reactivará el proc. que lleve más tiempo<br />

esperando.<br />

• Cada proc. en cola obtendrá eventualmente su turno → No<br />

inanición.<br />

●<br />

condición.queue<br />

– Función booleana = V → Hay algún proc. esperando en<br />

condición.


2. Sincronización en Monitores<br />

2.1.4. Colas <strong>de</strong> condición con prioridad<br />

• Propiedad FIFO: evita inanición.<br />

• Mayor control sobre estrategia <strong>de</strong> planificación: prioridad <strong>de</strong>l proceso<br />

en espera como nuevo parámetro.<br />

• Formato: Nombre_var_condición.wait (prioridad:integer);<br />

• Signal reanuda proceso que especificó el valor más bajo <strong>de</strong> prioridad.<br />

• Precaución diseño monitor: Evitar riesgos como la inanición.<br />

• Justificación:<br />

– Ningún efecto sobre la lógica <strong>de</strong>l programa: Funcionamiento<br />

similar con/sin colas <strong>de</strong> prioridad. Sólo mejora características <strong>de</strong>p.<br />

<strong>de</strong>l tiempo.<br />

– Or<strong>de</strong>nación automática cola: técnica <strong>de</strong> planificación rápida y<br />

sencilla, excepto si la cola es muy larga.<br />

– Almacenamiento requerido por proceso: una palabra


2. Sincronización en Monitores<br />

2.1.4. Colas <strong>de</strong> condición con prioridad (cont.)<br />

Ejemplo: Reloj con alarma. El proc. llamador se retarda n unida<strong>de</strong>s <strong>de</strong><br />

tiempo.<br />

monitor <strong>de</strong>spertador;<br />

var ahora: integer; <strong>de</strong>spertar: condicion;<br />

procedure <strong>de</strong>spiertame (n: integer);<br />

var alarma: integer;<br />

{alarma := ahora + n; while ahora


2. Sincronización en Monitores<br />

2.1.4. Colas <strong>de</strong> condición con prioridad (cont.)<br />

Ejemplo: Asignación recurso "siguiente trabajo el más corto".<br />

monitor asignador;<br />

var libre: boolean; turno: condicion;<br />

procedure petición (tiempo: integer);<br />

{if not libre then turno.wait (tiempo); libre:=false;}<br />

procedure liberar;<br />

{libre := true; turno.signal;}<br />

begin<br />

libre:= true;<br />

end;


2. Sincronización en Monitores<br />

2.2. Efecto <strong>de</strong> las operaciones <strong>de</strong> sincr. sobre la E.M. <strong>de</strong>l monitor<br />

• Requisito <strong>de</strong> reanudación inmediata<br />

– Un Signal <strong>de</strong>berá ir seguida inmediatamente por la reanudación <strong>de</strong> un proceso en espera,<br />

sin que exista la posibilidad <strong>de</strong> que intervenga la llamada a un procedimiento <strong>de</strong> un tercer<br />

proceso.<br />

• Única forma <strong>de</strong> garantizar que procesos en espera puedan adquirir un recurso que<br />

acaba <strong>de</strong> ser liberado → Evita inanición.<br />

• Propuesta <strong>de</strong> Hoare<br />

– Un proceso suspendido <strong>de</strong>bido a ejecución <strong>de</strong> signal, entrará en una cola <strong>de</strong> suspendidos<br />

en Signal. Cada proceso antes <strong>de</strong> salir <strong>de</strong>l monitor y liberar la E.M., comprueba si hay<br />

procesos en esta cola, si los hay, heredarán la E.M. Los procesos suspendidos al ejecutar<br />

una operación signal tienen prioridad sobre los que intentan entrar.<br />

• Propuesta <strong>de</strong> Brinch-Hansen<br />

– Signal sólo como última instrucción <strong>de</strong>l cuerpo.<br />

– Evita cola <strong>de</strong> suspendidos en signal → + Eficiencia


2. Sincronización en Monitores<br />

2.2.1. Problema <strong>de</strong> Anidación <strong>de</strong> llamadas en monitores<br />

• Sistema estructurado como colección jerárquica <strong>de</strong> monitores:<br />

procs. <strong>de</strong> un monitor pue<strong>de</strong>n llamar a otro<br />

• Problema:<br />

– Una llamada <strong>de</strong> monitor anidada se suspen<strong>de</strong> en el último monitor. La<br />

E.M. en el último se abandonará pero no en el monitor <strong>de</strong>s<strong>de</strong> el que<br />

se llama.<br />

– Los procesos que intenten llamar a procedimientos <strong>de</strong> cualquier<br />

monitor <strong>de</strong> la ca<strong>de</strong>na se bloquearán.<br />

– Menor concurrencia → Menor rendimiento.


2. Sincronización en Monitores<br />

2.2.1.1. Problema <strong>de</strong> Anidación. Propuestas <strong>de</strong> solución<br />

a) Prohibir llamadas anidadas.<br />

b) Liberar exclusión mútua en todos los monitores implicados en la ca<strong>de</strong>na y bloquear<br />

proceso.<br />

– Una vez señalado, el proceso necesitará readquirir el acceso exclusivo a todos los<br />

monitores.<br />

– Requerirá que el invariante <strong>de</strong>l monitor se establezca antes <strong>de</strong> cualquier llamada que<br />

pueda bloquear.<br />

c) Monitores = herramienta <strong>de</strong> estructuración para recursos compartidos. E.M. →<br />

sólo forma <strong>de</strong> preservar integridad <strong>de</strong>l recurso.<br />

– Hay casos en los cuales las operaciones <strong>de</strong> un monitor pue<strong>de</strong>n ejecutarse<br />

concurrentemente sin efectos adversos.<br />

– Definir construcción que permita especificar que ciertas operaciones se podrán ejecutar<br />

concurrentemente y la exclusión mútua se liberará.


2. Sincronización en Monitores<br />

2.3. Equivalencia entre semáforos y monitores<br />

• Los monitores pue<strong>de</strong>n ser implementados por semáforos.<br />

• Garantizar la E.M.<strong>de</strong> los cuerpos los procedimientos<br />

– Para cada monitor → Semáforo binario mutex (inic. a 1) para asegurar<br />

exclusión mútua entre los cuerpos <strong>de</strong> procedimientos.<br />

• mutex:bin_sem=1<br />

• ENTRADA Proc. → P(mutex)<br />

• SALIDA<br />

Proc. → Normalmente V(mutex)


2. Sincronización en Monitores<br />

2.3. Equivalencia entre semáforos y monitores (cont.)<br />

Propuesta <strong>de</strong> Hoare:<br />

– Semáforo urgente (inic. a 0) para cola <strong>de</strong> bloqueados en Signal<br />

– Contador procs. esperando en urgente (conturgente, inic. a 0).<br />

• Procesos que invocan un signal ejecutan:<br />

if (existen procs. bloqueados en wait) { conturgente ++;<br />

P(urgente) }<br />

• Para liberar procs. bloqueados en signal, antes <strong>de</strong> liberar la<br />

exclusión mútua, cada proceso ejecuta:<br />

if conturgente>0 V(urgente)<br />

else V(mutex);


2. Sincronización en Monitores<br />

2.3. Equivalencia entre semáforos y monitores (cont.)<br />

• Para cada variable condición <strong>de</strong>l monitor:<br />

– Semáforo semcondición (inic. a 0) para cola <strong>de</strong> bloqueados en Wait<br />

– Contador <strong>de</strong> nº procs. esperando condición (contcondición inic. a 0).<br />

condición.signal<br />

conturgente + +;<br />

if contcondición>0<br />

{ V(semcondición);<br />

P(urgente); }<br />

conturgente - - ;<br />

condición.wait<br />

contcondición + +;<br />

if conturgente>0<br />

V(urgente)<br />

else V(mutex);<br />

P(semcondición);<br />

contcondición - -;


2. Sincronización en Monitores<br />

2.3.1. Equivalencia entre semáforos y monitores. Mejoras<br />

• Salida <strong>de</strong>l cuerpo <strong>de</strong> un procedimiento sin wait ni signal V(mutex)<br />

– conturgente no ha cambiado.<br />

• Salida cuando signal es la última instrucción <strong>de</strong>l cuerpo:<br />

if contcondición > 0 V(semcondición)<br />

(*) else if conturgente>0 V(urgente)<br />

else V(mutex);<br />

• No hay otro wait o signal en el cuerpo (*) pue<strong>de</strong> omitirse.<br />

• Propuesta <strong>de</strong> Brinch-Hansen<br />

– signal última operación <strong>de</strong>l cuerpo conturgente y urgente se omiten<br />

– Esta simplificación sugiere que todas las operaciones signal <strong>de</strong>berían siempre<br />

ser la última operación <strong>de</strong> un proc. <strong>de</strong>l monitor.


2. Sincronización en Monitores<br />

2.3.2. Semáforos v.s. Monitores<br />

• Equivalentes en potencia expresiva.<br />

• Motivación <strong>de</strong> uso Monitores: Claridad y fiabilidad.<br />

• Característica que no se pue<strong>de</strong> implementar en semáforos:<br />

Suposición FIFO sobre la cola.


2. Sincronización en Monitores<br />

2.4. Problemas paradigmáticos resueltos con monitores<br />

2.4.1. Productor/consumidor utilizando un buffer circular<br />

program productorconsumidor;<br />

monitor buffercircular;<br />

CONST tamaño=...;<br />

VAR b:array [0..tamaño-1] of integer; in, out, n: integer; novacio, nolleno:<br />

condicion;<br />

procedure añadir (v:integer);<br />

{if (n==tamaño) nolleno.wait; /* Espera a que no esté lleno*/<br />

b[in] = v; in = (in + 1) % tamaño; n ++; novacio.signal;}<br />

procedure tomar(var v:integer);<br />

{if (n==0) novacio.wait; /* Espera a que no esté vacío */<br />

v = b[out]; out = (out + 1) % tamaño; n --; nolleno.signal;}<br />

{in = out = n = 0}


2. Sincronización en Monitores<br />

2.4.1. Productor/consumidor utilizando un buffer circular (cont.)<br />

procedure productor;<br />

VAR v: integer;<br />

{while (true) {producir(v);añadir(v)}<br />

procedure consumidor;<br />

VAR v:integer;<br />

{while (true) {tomar(v);consumir(v) }<br />

{ cobegin /* programa principal*/<br />

productor; consumidor;<br />

coend; }


2. Sincronización en Monitores<br />

2.4.2.Problema <strong>de</strong> los lectores/escritores sin priorida<strong>de</strong>s (FIFO).<br />

program lectoresescritores;<br />

monitor leerescribir;<br />

VAR lectores: integer; escribiendo: boolean; okleer, okescribir: condicion;<br />

procedure comenzarleer;<br />

{if (escribiendo or okescribir.queue) okleer.wait;<br />

lectores + +; okleer.signal}<br />

procedure finleer; {lectores - -; if (lectores==0) okescribir.signal;}<br />

procedure comenzarescribir;<br />

{if (lectores!=0 or escribiendo) okescribir.wait;<br />

escribiendo= true }<br />

procedure finescribir;<br />

{escribiendo = false; if (okleer.queue) okleer.signal else okescribir.signal }<br />

{lectores =0;<br />

escribiendo = false}


2. Sincronización en Monitores<br />

2.4.2.Problema <strong>de</strong> los lectores/escritores sin priorida<strong>de</strong>s (FIFO).cont.<br />

procedure procesolector;<br />

{ while (true) {comenzarleer; leerdatos; fin leer;}<br />

procedure procesoescritor;<br />

{ while (true) { comenzarescribir; escribirdatos; finescribir }<br />

{cobegin<br />

procesolector; procesolector; ...<br />

procesoescritor; procesoescritor; ...<br />

coend; }


2. Sincronización en Monitores<br />

2.4.3. Implementación con semáforos <strong>de</strong>l productor/consumidor<br />

• Propuesta <strong>de</strong> Brinch Hansen(/*signal es la última instrucción*/<br />

program productorconsumidor;<br />

CONST tamaño=...;<br />

VAR b: array [0..tamaño-1] of integer; in, out, n: integer;<br />

s: semaphore; /para E.M.*/<br />

semnovacio, semnolleno: semaphore; /* binarios */<br />

contnovacio, contnolleno: integer;<br />

procedure añadir (v:integer);<br />

{ P(s); if (n==tamaño) { contnovacio+ +; V(s); P(semnovacio); contnovacio --}<br />

b[in] = v; in := (in + 1) % tamaño; n + +;<br />

if contnolleno>0 V(semnolleno) else V(s);}<br />

procedure tomar(var v:integer);<br />

{ P(s); if (n==0) {contnolleno + +; V(s); P(semnolleno); contnolleno - -}<br />

v := b[out]; out := (out + 1) % tamaño; n := -- ;<br />

if contnovacio>0 V(semnovacio) else V(s); }


2. Sincronización en Monitores<br />

2.4.3. Implementación con semáforos <strong>de</strong>l productor/consumidor<br />

procedure productor;<br />

var v: integer;<br />

{while (true) {producir(v); añadir(v)}<br />

procedure consumidor;<br />

var v:integer;<br />

{while (true) {tomar(v); consumir(v)}<br />

{in =out=n = 0; s = 1;<br />

contnolleno = semnolleno = 0;<br />

contnovacio = semnovacio = 0;<br />

cobegin<br />

productor;<br />

consumidor;<br />

coend;}

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!