EDIT: ho risolto tutto scrivendo il post, non serve che ve lo leggiate

Allora, il progetto è praticamente finito, restano da sistemare robette ma niente di che, eccetto una cosa.
È un progetto che simula dei protocolli di sicurezza in una rete wireless di sensori sarcazzo, ma alla fine non serve saperlo con quello che devo chiedere.
Provo a spiegare la situazione.
Node: thread, agisce concorrentemente su altri Node, ogni tanto va in wait (quando ha il buffer dei messaggi ricevuti da elaborare vuoto), può essere svegliato da altri node (quando, dopo un inserimento, il buffer ha 1 messaggio), può terminare (this.interrupt) quando finisce l'energia.
Hypervisor: thread, crea n Node (in base a dei parametri di configurazione, di solito 100+) e li fa partire.
CheckAlive: classe interna a Hypervisor, thread, controlla periodicamente che i nodi stiano ancora facendo qualcosa.
In pratica, partito tutto, la simulazione deve terminare per 2 motivi:
- O è stato sgamato un intruso, e fin qua, nessun problema
- O CheckAlive trova che tutti i nodi sono o morti o non hanno più messaggi da elaborare.
Di fatto, funziona tutto benissimo così.
Teoricamente, però (e di sicuro il prof alzerebbe il dubbio) potrebbe succedere che, quando checkalive inizia a scorrere i nodi per controllare lo stato, arriva al ksimo nodo ( k = n/2 per esempio) e li ha trovati tutti in wait (quindi hanno il buffer vuoto) e/o terminati. Supponiamo che abbiano energia infiita, quindi li ha trovati tutti in wait. Quando il for inizia a esaminare il k+1esimo nodo, il k+10 invia un messaggio al k (e quindi lo sveglia) e torna a dormire (aveva solo un messaggio da spedire). Il for continua, arriva a n, e, "secondo lui" li ha trovati tutti in wait e interrompe la simulazione.
Però, sempre in teoria, quel messaggio sta praticamente andando in flooding (con bassissime probabilità potrebbe accadere per come funzionano i protocolli) e ha svegliato un casino di nodi, quindi la simulazione è viva e vegeta.
Soluzioni che mi erano venute in mente:
- mettere il controllo di checkalive dentro un blocco synchronized su un qualche oggetto, e conseguentemente anche l'invio di messaggi dei nodi sempre synchronized su quell'oggetto: funzionerebbe, ma sarebbe una schifezza, andrebbe praticamente sempre un solo nodo alla volta, la simulazione rallenterebbe un casino, una merda insomma.
- Soluzione che è venuta a me e anche ad altra gente: quando un nodo va in wait, subito prima chiama un metodo sincronizzato del supervisore che incrementa (o decrementa) un contatore, quando si sveglia il contrario. Checkalive quindi dovrebbe solo controllare un intero, un'operazione atomica, non ci sarebbero problemi. Idea interessante, molto figa, semplice da implementare.
Non funziona, ne a me né agli altri.
Non riusciamo a capire perché, ma il contatore arriva a valori assurdi (va sottozero o addirittura supera n). Mi fa davvero girare le balle che succeda, anche perché un thread non potrà mai, per esmpio, incrementare due volte di fila o decrementare due volte di fila, in quanto fa incremento-wait-decremento ( o il contrario, non cambia), poi fa le cose che deve fare, e al giro successivo del run fa di nuovo incremento-wait-decremento se ha il buffer vuoto e poi viene riempito, incremento-wait e basta se è vuoto e non viene riempito, nessun incremento/decremento se il buffer non era vuoto. Vi mostro il codice, se ci arrivate, vincete 12 internet.
Codice:
public void run(){
hv.wokeUp(id); //nasco
// faccio cose
while(alive){ // ci sarebbero altri controlli nel while, ma non sono utili per quello che vi devo chiedere
synchronized (waitingMessages) { //ottengo il lock sul buffer
if(waitingMessages.isEmpty()){
hv.goneSleep(id); //dormo
waitingMessages.wait();
hv.wokeUp(id); //mi sveglio (ho ricevuto una notify)
}
}
//ok mi sono svegliato, faccio quello che devo fare
//
//cose....
//
}
//se arrivo qua, è perchè !alive, quindi sono morto perché ho finito l'energia, ma voi fregatevene, fate conto che ho infinita energia.
hv.goneSleep(id);//muoio
this.interrupt();
}
ho omesso tutto il codice che non c'entra (inclusi tutti i vari try catch, in ogni caso ho controllato, non entrava mai nel catch)
vi mostro anche gonesleep e wokeup, anche se insomma, non è che ci sia tanto da mostrare
Codice:
synchronized void wokeUp(Integer id){
synchronized (nWorking) {
nWorking++;
System.out.println(id.toString().concat(" - nasco/sveglio, nworking= ").concat(nWorking.toString()));
}
}
synchronized void goneSleep(Integer id){
synchronized (nWorking) {
nWorking--;
System.out.println(id.toString().concat(" - muoio/dormo, nworking= ").concat(nWorking.toString()));
}
}
W Gesù INIZIALIZZAVO NWORKING A 0 FUORI DAL CICLO DI SIMULAZIONI
ME NE SONO ACCORTO ORA
funziona tutto
