PDA

View Full Version : [Java] Semaforo FIFO


alifangelo
23-10-2008, 17:15
Ciao a tutti, sto cercando di implemetare un semaforo FIFO cioè ogni volta che si esegue la signal viene risvegliato il thread che è in attesa da piu tempo.
L'idea è quella di creare un array circolare di object e mettere in cima i thread che si bloccano e sbloccarli dalla coda ottendo così la gestione FIFO.
Vi espongo il codice che sarà sicuramente piu chiaro

public class Semaphore {
public static final int SIZE = 100;
private int count = 0;
private String name;
private Object coda[] = null;
private int tail = 0;
private int head = 0;

public Semaphore(int count, String name) {
this.count = count;
this.name = name;
this.coda = new Object[SIZE];
for (int i = 0; i < SIZE; i++)
coda[i] = new Object();
}

public void swait() {
int heado;
synchronized (coda[head]) {

count -= 1;
if (count < 0)
try {
heado = head;
head = (head + 1) % SIZE;
System.out.println( " - bloccato "+thread.currentThread());
coda[heado].wait();
}

catch (Exception e) {
System.out.println( e+" - eccez. nella swait";
}
}
}

public void signal() {
synchronized (coda[tail]) {
count += 1;
if (count <= 0) {
coda[tail].notify();
tail = (tail + 1) % SIZE;
}
System.out.println(" fine signal: " + Thread.currentThread());
}
}

}

//codice thread
public class Mythread extends Thread{
private Semaphore semaforo;

public Mythread( Semaphore semaforo){
this.semaforo=semaforo;
}

public void run (){

semaforo.swait();
System.out.println( " sto dormendo " + Thread.currentThread());
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
System.out.println( " eccez. nella sleep " + Thread.currentThread());
e.printStackTrace();
}
semaforo.signal();
}
}
// il MAIN
public class Test {
public static void main(String[] args){
Semaphore s=new Semaphore(1,"semaforo");

Mythread A= new Mythread(s);
A.start();
Mythread B= new Mythread(s);
B.start();
Mythread C= new Mythread(s);
C.start();
Mythread D= new Mythread(s);
D.start();
Mythread E= new Mythread(s);
E.start();
Mythread F= new Mythread(s);
F.start();
}
}

il problema è che nella swait viene generata un'eccezione quando eseguo coda[heado].wait(); L'eccezione è java.lang.IllegalMonitorStateException ma non riesco a capire il perchè, esce random, cioè alcune volte va altre no.
vi posto un run con cosa mi esce

sto dormendo Thread[Thread-0,5,main]
bloccato Thread[Thread-2,5,main]
bloccato Thread[Thread-3,5,main]
java.lang.IllegalMonitorStateException - eccez. nella swait Thread[Thread-3,5,main]
sto dormendo Thread[Thread-3,5,main]
bloccato Thread[Thread-4,5,main]
java.lang.IllegalMonitorStateException - eccez. nella swait Thread[Thread-4,5,main]
sto dormendo Thread[Thread-4,5,main]
bloccato Thread[Thread-5,5,main]
bloccato Thread[Thread-1,5,main]
java.lang.IllegalMonitorStateException - eccez. nella swait Thread[Thread-1,5,main]
sto dormendo Thread[Thread-1,5,main]
fine signal:Thread[Thread-0,5,main]
sto dormendo Thread[Thread-2,5,main]
fine signal: count = -3Thread[Thread-4,5,main]
fine signal: count = -2Thread[Thread-3,5,main]
fine signal: count = -1Thread[Thread-1,5,main]
sto dormendo Thread[Thread-5,5,main]
fine signal: count = 0Thread[Thread-2,5,main]
fine signal: count = 1Thread[Thread-5,5,main]

Se qualcuno saprebbe darmi una spiegazione gliene sarei grato.
Vi ringrazio anche se solo avete letto tutto quello che ho scritto :D

Già che ci sono volevo chiedervi se dopo che un thread viene risvegliato da una notify prosegue il suo codice dopo la wait giusto? Ma a quel punto ha di nuovo il lock dell'oggetto ?

U-Boat
23-10-2008, 21:19
Già che ci sono volevo chiedervi se dopo che un thread viene risvegliato da una notify prosegue il suo codice dopo la wait giusto? Ma a quel punto ha di nuovo il lock dell'oggetto ?
Sì, quando un thread si risveglia continua la sua esecuzione dall'istruzione successiva alla wait quando può ottenere il lock sull'oggetto.

Parlando del tuo codice, non sono troppo convinto che funzioni, ma adesso non ho troppa voglia di mettermi a fare un'analisi esaustiva... così a naso vedo che le wait non sono in un ciclo e usi tantissimi lock diversi anche per le variabili condivise, con potenziali problemi di visibilità.

Il problema che hai invece dovrebbe essere questo: metti di avere tre thread, A, B e C, che partono assieme.

A entra nel blocco sync con il lock sul primo oggetto della coda (cioè coda[0], mentre gli altri due sono in attesa sullo stesso oggetto.
A esce dal blocco ed entra B che aggiorna l'indice della testa e si mette in attesa su coda[0].
C entra nel blocco e cerca di mettersi in wait su coda[1], ma il lock lo possiede su coda[0], quindi ti lancia l'eccezione.