Ciao a tutti sto impazzendo su questo progetto per l'uni. teoricamente è gia pronto se non fosse per un solo dei molteplici punti che lo compongono e mi sta facexndo sfasare di brutto.
vi posto le specifiche.
Il progetto è composto da 4 parti da svolgere un stretta sequenza (la parte in rosso è quella incriminata):
Parte prima ?
-Implementare la classe FairSemaphore che definisce un semaforo generale assicurando che la gestione dei thread sospesi sul semaforo sia rigorosamente First-In-First-Out.
-Per l’implementazione della classe FairSemaphore devono essere utilizzati esclusivamente i meccanismi di sincronizzazione offerti da Java versione 4.0 (blocchi e/o metodi synchronized, metodi wait(), notify() e notifyll() ) .
Parte seconda ?
- Utilizzando come meccanismo di sincronizzazione esclusivamente i semafori (come implementati nella parte prima), implementare la classe SynchPort che simula una porta sincronizzata.
- La porta deve essere generica rispetto al tipo T di informazione scambiata (class SynchPort<T>)
- Ogni porta deve essere dichiarata come oggetto public locale al thraed (processo) ricevente. La porta deve essere infatti visibile a ciascuno dei processi mittenti che dovranno invocare il metodo send sulla specifica porta.
- Il numero di mittenti deve essere passato come parametro al costruttore della porta.
-Il metodo receive deve restituire al processo ricevente l’informazione di tipo <T>contenuta nel messaggio ricevuto e l’identificazione del processo mittente.
Parte terza
-Implementare la classe PortVector che definisce un array di porte sincronizzate da usare poi, nella parte quarta, come array di porte attraverso le quali un processo server riceve richieste di servizio. Per questo, locale ad un processo server verrà dichiarato un oggetto (public) di tipo PortVector ?
-Il numero N delle porte componenti il vettore è passato come parametro al costruttore della classe.?
-Per semplicità, tutte le porte del vettore vengono definite con lo stesso numero di processi mittenti (il numero dei clienti del server).?
-Ogni processo mittente (cliente) invia i propri messaggi ad una delle porte dell’array identificata, oltre che dall’identificatore dell’oggetto di tipo PortVector anche dal suo indice nell’array stesso. .?
-Il processo ricevente (server) utilizza, per ricevere messaggi, il metodo Receive a cui vengono passati come parametri, fra l’altro, un vettore di interi vet e un intero n.
n rappresenta la dimensione del vettore vet (1>=n>=N). Gli elementi di vet sono n interi che rappresentano gli indici delle porte (indici di elementi del vettore PortVector) da cui si vuol ricevere.
La receive è bloccante se su nessuna delle porte indicate esiste un mittente pronto a inviare un messaggio. In questo caso il processo ricevente verrà svegliato quando sarà possibile ricevere da una qualunque delle porte indicate.
Se, viceversa, da una o da più di una delle porte è possibile ricevere, ne viene scelta una a piacere e viene ricevuto il messaggio da tale porta.
Di nuovo, la receive deve restituire al processo ricevente l’informazione di tipo <T> contenuta nel messaggio ricevuto e l’identificazione del processo mittente, ma in questo caso, deve essere restituito anche l’indice della porta dell’array dalla quale il messaggio è stato ricevuto.
Parte quarta la ometto
e qui posto il codice
import java.util.Vector;
public class portvector<T> {
Vector<Synchport<T>> porte;
int n_mess[];
FairSemaphore Rcv, mutex;//deve in qualche modo diventare un semaforo binario
int porteAttese[];
boolean firstAccess;
//costruttore della classe
public portvector(int n_m, int n_p) {
porte= new Vector<Synchport<T>>(n_p);
n_mess=new int[n_p];
firstAccess=false;
porteAttese= new int [n_p];
for (int j=0;j<n_p;j++)
{
porte.add(new Synchport<T>(n_m));
n_mess[j]=0;
porteAttese[j]=0;
}
Rcv=new FairSemaphore("Rcv", 0);
mutex=new FairSemaphore("mutex",1);
}//fine costruttore
public PortData<T> receive(int vet[], int n) throws InterruptedException // non funziona ancora
{ /// qui uso la tecnica del passaggio del testimone
mutex.P();
firstAccess=true;
for ( int i = 0; i<n;i++)
porteAttese[vet[i]]=porteAttese[vet[i]]+1;//segna preventivamente su quali porte il ricevitore vuole ricevere un messaggio
while (true)
{
for (int i = 0; i<n;i++)
{
if (n_mess[vet[i]]>0)//vuol dire che la porta di indice vet[i] contiene almeno un mess
{
n_mess[vet[i]]=n_mess[vet[i]]-1;
for (int j = 0; j<n;j++)
{porteAttese[vet[j]]=porteAttese[vet[j]]-1;//elimina l'attesa preventiva dalle porte in quanto ha ricevuto il mess atteso
}
//System.err.print("\n");
PortData<T> temp=porte.elementAt(vet[i]).receive();
firstAccess=false;
mutex.V();
return temp;
}
}//fine for
if (firstAccess)// implementa la tecnica del passaggio del testimone.
{
firstAccess=false;
mutex.V();
}
else
Rcv.V();
Rcv.P();//non ci sono messaggi nelle porte specificate dunque il processo ricevente si blocca sul semaforo Rcv
//mutex.P();
}// fine while
}//fine receive
public void send(int i,PortData<T> p) throws InterruptedException {
mutex.P();
n_mess[i]=n_mess[i]+1;//indica che sulla porta i-esima è presente un altro messaggio
if (porteAttese[i]>0)
Rcv.V();//avverte il ricevente che un nuovo messaggio è presente nella porta;
mutex.V();//rilascia il lock sull oggetto
porte.elementAt(i).send(p);
}//fine send
}//fine class portvector
e due parole sul funzionamento
All'interno della classe portvector troviamo.
• Un vettore di porte sincronizzate cui i vari client inviano messaggi.
• Un semaforo di mutua esclusione per l'accesso esclusivo all'oggetto portvector.
• Un semaforo Rcv in cui i lettori possano mettersi in attesa di messaggi.
• Un array di interi porteAttese: questo array indica le porte da cui il ricevitore desidera ricevere messaggi in un determinato istante
• Un vettore n_mess con dimensione pari a quella del vettore delle porte, che indica, alla posizione j, il numero di messaggi non letti all'interno della j-esima porta.
• Il buleano firstAccess: il suo ruolo sarà più chiaro nella spiegazione della Receive.
Il meccanismo della send è molto più semplice rispetto alla receive. Infatti, il mittente deve "solo" inviare l'informazione ,sulla porta di indice "i", incrementando il contatore dei messaggi (n_mess) associato alla porta, nel caso in cui tale porta fosse desiderata da un ricevitore deve effettuare una V() sul semaforo Rcv senza rilasciare la mutua esclusione, la quale verrà gestita da l thread lettore(tecnica del passaggio del testimone) in modo da risvegliare il ricevitore avvertendolo della presenza di un nuovo mesaggio, in caso contrario rilascia semplicemente la mutua esclusione.
Come indicato dal testo, il metodo receive() deve essere bloccante, vale a dire, se il ricevitore non trova messaggi in nessuna delle porte da cui ha deciso di ricevere, allora dovrà mettersi in attesa dell’arrivo di un messaggio da una qualunque delle porte indicate nel vettore vet.
un ricevitore che voglia ricevere da un set di porte, invocando la receive() dopo aver preso la mutua esclusione sull'oggetto, eseguirà una fase preliminare incrementando di 1 il contatore associato alle porte da cui aspetta un messaggio, questo viene logicamente fatto al difuori del ciclo while perché altrimenti ad ogni iterazione del ciclo tale fase porterebbe a risultati falsati.
Adesso il thread entra nel ciclo infinito del while.
Il thread a questo punto controllerà se sulle porte desiderate esistono dei messaggi.
Se sono presenti messaggi, su una qualunque delle porte desiderate, allora invocherà la receive propria di tale porta e ritornando il pacchetto di informazioni uscirà dal ciclo, naturalmente non prima di aver decrementato i contatori associati alle porte desiderate (opposta alla fase di attesa preventiva) e aver rilasciato la mutua esclusione sull'oggetto.
Se invece non sono presenti messaggi sulle porte desiderate (indicate dal vettore vet) allora il ricevitore essendo al primo si metterà in attesa sul semaforo Rcv.
Nel momento in cui uno dei mittenti invia un messaggio su una delle porte attese allora il ricevitore in attesa svegliatosi rientra nel ciclo, riesegue la fase di controllo e se trova un messaggio sulla porta desiderata allora esce dal metodo receive e rilascia la mutua esclusione. Se invece non ne trova questa volta sveglierà un altro ricevitore e si rimetterà in attesa sul semaforo RcV. La mutua esclusione non viene rilasciata e tale compito viene subordinato al thread appena svegliato implementando come nel caso della send la “tecnica del passaggio del testimone”.
In questa fase si ha la certezza che almeno uno dei ricevitori leggerà un messaggio dato che il mittente effettua una P() sul semaforo RcV se e solo se almeno un ricevitore è in attesa sulla porta da lui usata.
alla fine del while si fa la P() sul semaforo binario mutex, questo per garantire la mutua nell'unico caso in cui due thread operino sull'oggetto in contemporanea. infatti senza la P(mutex) se un thread accedesse all'oggetto e un thread bloccato si risvegliasse avremmo due thread che contemporaneamente agiscono sull'oggetto condiviso (il portvector)
i semafori usati sono di tipo FIFO e funzionano (testati in molti modi), come le porte sincronizzate(Synchport). all'interno delle porte sincronizzate ci sono due metodi send e receive. nella send un mittente rimane bloccato su un semaforo interno alla porta finchè il ricevente non estre il messaggio attraverso il metodo receive. analogamente con la receive un ricevente che lo usa si metterà in attesa su un altro semaforo interno se non sono presenti messaggi, in pratica uso la tecnica del rendez vous.
è tanta roba lo so e spero innanzitutto di esser stato chiaro e che voi siate in grado di aiutarmi. ne va della mia salute mentale.
il problema è che a un certo punto tutto si blocca e nessuno riesce ad andare avanti. come se pur essendoci messaggi in una qualche porta ilo ricevitore in attesa non riesce a vederlo