Monitores
Idea desarrollada en los años 70 Brinch-Hansen y Hoare <ref>http://java.sun.com/developer/Books/performance2/chap4.pdf</ref>que notaron los siguientes problemas con respecto al uso de los semáforos:
- Los semáforos son difíciles de usar. Es frecuente que el programador cometa errores al emplearlos.
- El compilador no asiste al programador en el desarrollo de programas concurrentes mediante semáforos, pues no ofrece ningún tipo de validación en tiempo de compilación.
- No hay nada que obligue a usarlos. Puede suceder que el programador los necesite y lo desconozca
- Son independientes del recurso compartido
Los monitores tienen que estar integrados en el lenguaje de programación.
Definición
Un monitor es una estructura del lenguaje cuyas principales características son:
- Los datos son privados.
- Ofrecen una serie de métodos públicos para acceder a dichos datos.
- En cada momento sólo puede haber un proceso activo en algún método del monitor, es decir, ejecutando código de esos métodos públicos del monitor. Seria equivalente a decir que el recurso que queremos compartir se declara como monitor. Los procesos que usan el monitor son independientes unos de otros y cuando deseen usar el recurso, llamarán a los métodos del monitor que implementen la operación que se desea ejecutar.
Permiten organizar procesos en espera mediante:
- Variables de condición: lista de procesos inicialmente vacía.
- Primitivas: wait(c), añade el proceso p invocante a c y proceso p bloquea; signal(c), selecciona a uno de los procesos en c y lo pone en preparado.
class recursoCompartido {
public int get(void);
public void set(int valor);
private int recursoCompartido;
private Semaforo s = 1;
public int get(void){
int ret;
down(s);
ret = recursoCompartido;
up(s);
return ret;
}
public void set(int valor){
down(s);
recursoCompartido = valor;
up(s);
}
}
Como vemos, los monitores se implementan con semáforos, son una abstracción de los mismos.
Ejemplo en Java
Ejemplo de sincronización mediante monitores con 5 hilos que modifican dos variables. Cada hilo incrementa las dos variables una unidad. El hilo principal va mostrando el contenido de las variables. Si quitamos la clausula synchronized podemos ver como las variables no se incrementan a la vez.
public class Principal {
public static void main(String[]args){
RecursoCompartido c = new RecursoCompartido();
for(int i=0;i<5;i++){
new Hilo(c);
}
while(true){
c.mostrar();
try{
Thread.sleep(20);
}catch(InterruptedException e){}
}
}
}
class Hilo extends Thread{
static int i=0;
int h;
RecursoCompartido c;
public Hilo(RecursoCompartido c){
this.setDaemon(true);
this.c=c;
h=i++;
this.start();
}
public void run(){
while(true){
c.incrementar();
//System.out.println("Ahora se está ejecutando el hilo "+h);
try{
sleep(20);
}catch(InterruptedException e){
}
}
}
}
class RecursoCompartido{
private int a = 0;
private int b = 0;
public synchronized void incrementar(){
a++;
b++;
}
public void mostrar(){
System.out.println("a: "+a+"\tb: "+b);
}
}
Fuentes
<references/>