domingo, 22 de mayo de 2005

sábado, 21 de mayo de 2005

Java Semaphores, Productor Consumidor


Trabajaremos con el paquete java.util.concurrent.Semaphore;

Algunos conecptos basicos sobre Semaforos:

Un semáforo es una variable especial protegida que constituye el método clásico para restringir o permitir el acceso a recursos compartidos (por ejemplo, un recurso de almacenamiento del sistema o variables del código fuente) en un entorno de multiprocesamiento (en el que se ejecutarán varios procesos concurrentemente). Fueron inventados por Edsger Dijkstra .

Un semaforo dispone de un contador de tipo Integer y de un array de procesos bloqueados, si el contador del semaforo esta a 0 , los procesos que hagan acquire() en el , se dormiran en el array de procesos bloqueados, esperando a que otro proceso haga un release().
Cuando instanciamos un objeto de la clase Semaphore, podemos inicializar su contador, asi si lo hacemos a 2, los dos primeros procesos que hagan acquire() sobre el no se dormiran pero decrementaran el contador, el tercero consecutivamente que realize un acquire() sobre el contador, quedara dormido en el array de procesos bloqueados.

Un libro completo sobre semaforos lo podeis encontrar aqui: The Little Book of Semaphores

Un ejemplo de sincronizacion, es el mostrado en la siguiente figura:


Observamos como los Procesos P1y P3 precede al Proceso 2 y el 4 , es decir; los Procesos P2 y P4 no pueden arrancar hasta que P1 y P3 hayan terminado su seccion critica.
El codigo fuente sin semaforos de esta aplicacion seria; 4 clases que lanzaremos como procesos, ejecutaran un sleep
() simulando un procesamiento y luego imprimira el numero de proceso que es, identificando asi la salida.


1. Creacion de los procesos y l a clase lanzadora:

public class p1 extends Thread {
public void run() {
try {
sleep((int) Math.round(500 * Math.random() - 0.5));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("P1");
}
}

public class p2 extends Thread {
public void run() {
try {
sleep((int) Math.round(500 * Math.random() - 0.5));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("P2");
}
}

public class p3 extends Thread {
public void run() {
try {
sleep((int) Math.round(500 * Math.random() - 0.5));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("P3");
}
}

public class p4 extends Thread {
public void run() {
try {
sleep((int) Math.round(500 * Math.random() - 0.5));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("P4");
}
}

public class go {

/**
* @param args
*/
public static void main(String[] args) {
//Throw concurrente proccess
(new Thread(new p1())).start();
(new Thread(new p2())).start();
(new Thread(new p3())).start();
(new Thread(new p4())).start();
}

}

Al ejecutar la salida obtendremos distintos resultados, porque cada vez, cada proceso tardara mas o menos en ejecutar.

Posibles salidas: {P1,P2,P3,P4},{P2,P4,P1,P3},{P4,P3,P1,P2},..... cualquier combinacion es posible.


2. Sincronizacion de los procesos










Ahora las posibles salidas son : {P3,P1,P2,P4},{P1,P3,P4,P2},... como podemos observar se cumple perfectamente la sincronizacion requerida.



-