PDA

View Full Version : [Java]Concorrenza


pranzu
06-05-2006, 16:21
Riporto un esempio tratto da Thinking in Java e semplificato.

class SimpleSemaphore extends Thread {
public static volatile int semaphore = 0;
public SimpleSemaphore() {
this.setDaemon(true);
start();
}
public void run() {
while(true)
if(semaphore == 0) {
// yield();
++semaphore;
// yield();
--semaphore;
// yield();
}
}
public static void main(String args[]) {
new SimpleSemaphore();
new SimpleSemaphore();
new SimpleWatcher();
}
}

class SimpleWatcher extends Thread {
public SimpleWatcher() {
start();
}
public void run() {
while(true) {
int s = SimpleSemaphore.semaphore;
if(s == 0 || s == 1) {
} else {
System.out.println("Irregular Value: " + s);
System.exit(0);
}
}
}
}

Due thread SimpleSemaphore concorrono alla risorsa gestita dal semaforo e un terzo thread, SimpleWatcher, osserva se la variabile semaphore assume valori non validi (diversi da 0 e 1).
Commentando o no yield() e seconda di JVM e OS si possono osservare i valori non validi -1 e 2.
Mi spiego il valore 2 ma non il -1.
Qualcuno me lo spiega?

PGI-Bis
06-05-2006, 19:02
yield() lo possiamo macerare: con o senza non cambia nulla nel nostro caso. Che un thread dia l'occasione ad un altro di essere eseguito non significa che l'altro sia pronto in quel momento.

La scrittura volatile di una variabile è sincronizzata con tutte le letture successive di quella variabile.

L'operatore "++" e il suo compare "--" constano di due passaggi, un READ e un WRITE.

Le operazioni READ/WRITE eseguite dai Thread sono:

READ //if(semaforo == 0)
READ //parte READ dell'incremento
WRITE //parte WRITE dell'incremento
READ //parte READ del decremento
WRITE //parte WRITE del decremento

ogni WRITE è sincronizzato con i READ successivi. Assumendo che le operazioni coinvolte siano quelle indicate, detti Ta e Tb i due Thread che modificano il valore semaforo e Tc quello che stampa l'errore, un caso in cui l'ordine di sincronizzazione consente l'esistenza del valore -1 è:

Ta legge (0) - if
Tb legge (0) - if
Ta legge (0) - parte READ dell'incremento
Tb legge (0) - parte READ dell'incremento
Ta scrive (1) - parte WRITE dell'incremento
Tb scrive (1) - parte WRITE dell'incremento
Ta legge (1) - parte READ del decremento
Ta scrive (0) - parte WRITE del decremento
Tb legge (0) - parte READ del decremento
Tb scrive (-1) - parte WRITE del decremento
Tc legge (-1) - quando si dice "al momento giusto"...

Descrittivamente, capita quando lo schedulatore inizia distribuendo le prime operazioni "una a testa" e poi, per un colpo di fortuna :D, decide di passare a coppie di istruzioni.

pranzu
07-05-2006, 12:16
Grazie PGI :)
Spiegazione chiara e precisa.