21
Monitores

Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

  • Upload
    others

  • View
    8

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Monitores

Page 2: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Los semáforos, son el equivalente a las instrucciones goto y el manejo de apuntadores en los lenguajes de programación imperativos: son muy susceptibles a errores. Su utilización exige disciplina.

Por ejemplo, el siguiente error conduce inmediatamente a un deadlock:

P(S) ; sección crítica P(S);

Generalmente resulta difícil distinguir entre los dos usos de los semáforos (i.e. para exclusión mutua y condición de sincronización) en un programa sin una revisión detallada de todo el código.

Page 3: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores de programación, proporcionando construcciones de programación de mayor nivel de abstracción que los semáforos, ya que los monitores están en estrecha relación con la programación orientada a objetos, además de ser la primitiva para sincronización interconstruída que ofrece Java.

Page 4: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Definición de monitor

Un monitor es un módulo opaco que encapsula servicios mediante métodos de acceso, así como sus variables locales y globales.

La única forma para manipular o acceder las variables dentro del monitor es invocando alguno de los métodos de servicio.

Solamente se permite que un hilo esté activo a la vez dentro del monitor ejecutando uno de los métodos de servicio, asegurando exclusión mutua y previniendo implícitamente la presencia de condiciones de contención.

Cada objeto monitor tiene un candado, el compilador del lenguaje de programación genera el código al comienzo de cada método de servicio para adquirir el candado y al final para liberarlo.

Si el monitor está ocupado por algún hilo (i.e. se apropió del candado), los hilos siguientes que invoquen alguno de los métodos de servicio del monitor (i.e. intenten entrar al monitor) serán bloqueados e incorporados en la lista de espera para adquirir el candado.

Page 5: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Sincronización

Al igual que los semáforos, los monitores ofrecen

las dos formas de sincronización:

la exclusión mutua está garantizada por el compilador

implícitamente al invocar métodos de servicio.

Para proporcionar mecanismos para sincronización de

eventos (condición de sincronización) un monitor puede

contener variables de condición, las cuales pueden

manipularse mediante las operaciones signal y wait (que

son análogas a las operaciones P y V en semáforos

binarios, respectivamente).

Page 6: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Funcionamiento Su funcionamiento se describe enseguida:

wait: Un hilo que espera a que ocurra un evento indicado por una variable de condición deja al monitor temporalmente, libera el candado y se une a la lista de hilos bloqueados correspondiente a esa variable de condición.

signal: Cada señal con respecto a una variable de condición despierta a un hilo de la lista de hilos bloqueados correspondiente a esa variable de condición (no necesariamente el que lleva más tiempo en espera), si no hay ningún hilo esperando, la señal no se almacena y no tiene efecto (contrastando a la manera en la cual los semáforos funcionan).

Dado que las operaciones de liberar al candado y unirse a la lista de espera por una variable de condición son operaciones atómicas no hay riesgo de pérdida de las señales (i.e. `wakeup'). Al hilo despertado por la señal se le desplaza de esa lista de bloqueados y se le coloca en la lista de hilos en espera por entrar al monitor. Una vez que el candado sea readquirido, el hilo en cuestión continúa la ejecución del método de servicio que invocó anteriormente (i.e. la primera vez para entrar al monitor).

Page 7: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Estructura de un monitor

Las variables de condición de los monitores no tienen valor, se le puede considerar como el nombre de la lista de hilos bloqueados (nombre de un evento).

Page 8: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Diferencias con los semáforos

Note que las variables de condición y los semáforos

difieren en dos maneras:

una señal realizada en una variable cuya lista de hilos

bloqueados está vacía no tiene efecto mientras que la

invocación a V incrementa el contador del semáforo;

una invocación a la primitiva wait en una variable de

condición siempre bloquea al hilo hasta que reciba una

señal mientras que una invocación a P decrementa el

contador del semáforo si su valor es positivo y no bloquea

al hilo.

Page 9: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Disciplinas de señalización

El manejo de las variables de condición de los monitores se implanta de acuerdo a una de las diferentes disciplinas de señalización:

1. signal and exit: si un hilo que esté ejecutándose dentro del monitor emite una señal respecto una variable de condición entonces debe dejar el monitor inmediatamente ejecutando una instrucción return en el método de servicio que invocó. Se despierta a un hilo de la lista de hilos bloqueados correspondiente a la variable de condición y continúa ejecutándose dentro del monitor.

2. signal and wait: el hilo que recibe la señal (señalado o despertado) se ejecuta dentro del monitor, mientras que el hilo que emitió la señal (señalador) espera a que el señalado salga del monitor y entonces pueda continuar el señalador.

3. signal and continue: el hilo despertado espera a que el señalador deje el monitor y entonces continúa su ejecución dentro del monitor.

Page 10: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Disciplinas de señalamiento en los Monitores

Page 11: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Los monitores en Java utilizan la disciplina signal

and continue, pero revisaremos primero a la más

sencilla que es signal and exit.

Los métodos de servicio se indican con la palabra

reservada synchronized indicando que un sólo hilo

se le permite ejecutar el método a la vez, el método

wait(condVar) permite indicar la espera de una

variable de condición, por su parte notify(condVar)

indica la emisión de una señal.

Page 12: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Signal and exit

Para la disciplina signal and exit, se asume lo

siguiente:

Después de emitir una señal respecto una variable de

condición, el señalador debe salir inmediatamente del

monitor, de tal forma que ninguna variable cambia antes de

que el hilo despertado continúe ejecutándose dentro del

monitor. Por tanto, el hilo despertado encuentra que la

condición de la señal es verdadera.

Al hilo despertado se le otorga prioridad para proceder

inmediatamente al monitor sobre aquellos hilos que

estaban esperando entrar al monitor mediante la

invocación de un método de servicio.

Page 13: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Como ejemplo, mostramos (en pseudo código) un fragmento para la solución al problema del productor-consumidor utilizando un buffer limitado (archivo Monitor/bbse.java):

public synchronized void deposit(double data) {

if (count == size) wait(notFull);

buf[rear] = data;

rear = (rear+1) % size;

count++;

if (count == 1) notify(notEmpty);

}

public synchronized double fetch() {

double result;

if (count == 0) wait(notEmpty);

result = buf[front];

front = (front+1) % size;

count--;

if (count == size-1) notify(notFull);

return result;

}

Page 14: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Si el buffer está lleno, el productor se bloquea con

la invocación al método wait respecto a la variable

de condición notFull, el productor es despertado por

el consumidor mediante la señal notify cuando deja

un espacio libre en el buffer.

Si el buffer está vacío, el consumidor se bloquea

respecto la variable notEmpty y a su vez será

despertado por el productor cuando éste coloque un

elemento en el buffer.

Page 15: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Signal and continue Para la disciplina signal and continue, no se requiere que el hilo que emitió la señal salga

del monitor, ni tampoco que el hilo despertado tenga prioridad para proceder dentro del monitor sobre los demás hilos que están esperando entrar (compiten por el candado).

Por ello, no se puede garantizar que la condición que condujo la emisión de la señal continue siendo válida cuando el hilo que fué despertado entre de nuevo al monitor, ya que antes de dejar al monitor el hilo que emitió la señal podrá haber cambiado datos y/o alterado el estado interno del monitor.

A su vez, los hilos que compiten por entrar al monitor pueden adelantárseles a los hilos que están esperando a que ocurra el evento de la variable de condición, lo cual resulta en una forma de inanición (pues el tiempo de espera asociado a la variable de condición no está limitado).

Debido a ello, se deben tomar precauciones para que el hilo que estaba esperando por la variable de condición verifique que ésta haya ocurrido una vez que entra de nuevo al monitor, i.e. fundamentalmente se debe cambiar

if (condicion) wait(); // bloqueo en signal-and-exit

por un bucle:

while (condicion) wait(); // bloqueo en signal-and-continue

incluso permitiendo que la señal pueda despertar a más de un hilo bloqueado (i.e una forma de broadcast).

Page 16: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Monitor en Java Para construir un monitor en Java, se debe utilizar el modificador

synchronized en cada método de servicio (i.e que requiera exclusión mutua), tales métodos generalmente son públicos pero pueden también ser privados.

Cada objeto Java tiene un candado asociado; implícitamente, un hilo que quiera ejecutar un método synchronized de un objeto primero debe apropiarse del candado, bloqueándose si es que está en uso por otro hilo.

Desafortunadamente, cada monitor en Java sólo tiene una variable de condición anónima; todas las invocaciones a wait() y notify() (para bloquear y emitir una señal, respectivamente) se refieren automáticamente a esa variable anónima.

Por su parte, la primitiva notifyAll() permite despertar a todos los hilos que se encuentran bloqueados esperando por la variable de condición anónima.

Page 17: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Como ejemplo, se muestra segmentos de código para el problema productor- consumidor con buffer limitado (prog. Monitor/bbmo.java)

public synchronized void deposit(double value) {

while (count == numSlots)

try {

wait();

} catch (InterruptedException e) {

System.err.println("interrupted out of wait");

}

buffer[putIn] = value;

putIn = (putIn + 1) % numSlots;

count++; // wake up the consumer

if (count == 1) notify(); // since it might be waiting

}

public synchronized double fetch() {

double value;

while (count == 0)

try {

wait();

} catch (InterruptedException e) {

System.err.println("interrupted out of wait");

}

value = buffer[takeOut];

takeOut = (takeOut + 1) % numSlots;

count--; // wake up the producer

if (count == numSlots-1) notify(); // since it might be waiting

return value;

}

Page 18: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Patrón de diseño de los monitores en Java

public synchronized tipo metodo(...) {

...

notifyAll(); // si alguna condición de espera fue alterada

while(!condicion)

try { wait(); }catch (InterruptedException e) {}

...

notifyAll(); // si alguna condición de espera fue alterada

}

Page 19: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Objetos sincronizados

A pesar de que los monitores en Java solamente tienen una variable de condición anónima, se puede utilizar un objeto para implantar una variable de condición con nombre, que actuará como un objeto para notificación:

objeto compartido:

Object obj = new Object();

en un hilo: en el otro:

synchronized(obj) { synchronized(obj) {

if (!cond) if (cond) obj.notify();

try { obj.wait();} ...

catch(InterruptedException e){} }

...

}

Page 20: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Dentro de un bloque de exclusión mutua en

obj un hilo verifica la condición para ver si

puede continuar, de lo contrario espera.

El otro hilo cambia la condición y notifica al

hilo en espera.

Cuando se usa dentro de un monitor, un

objeto de notificación juega el rol de una

variable de condición con nombre.

Page 21: Monitores - Benemérita Universidad Autónoma de Pueblamtovar/doc/PCP/Monitores.pdf · Los monitores pretenden ayudar a evitar los riesgos a que se presentan esos tipos de errores

Deadlocks en monitores Cabe mencionar que las invocaciones anidadas a métodos de servicio de los

monitores están sujetos a deadlocks: class S { class T {

synchronized void f(T t) { synchronized void g(S s) {

... t.g(...); ... ... s.f(...); ...

}} }}

Aquí, s y t son referencias a monitores creados en las clases S y T respectivamente, y que son compartidos por dos hilos A y B en la siguiente secuencia de eventos:

A: invoca s.f(t);

B: invoca t.g(s);

A: se bloquea al invocar t.g

B: se bloquea al invocar s.f

Para evitar deadlocks, se sugiere ordenar globalmente todos los objetos monitor y solicitar que todos los hilos que compiten por el candado del monitor sigan el mismo orden.