Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2004
    Messaggi
    143

    [Java] uscire da wait()

    Ciao! ho delle difficoltà a realizzare un metodo che serve nel mio progetto. Il progetto consiste in un insieme di nodi che rappresentano i computer di una rete distribuita. Ogni nodo memorizza a livello locale la memoria che non è altro che un insieme di coppie String valore - int valore.
    Ogni volta che per esempio un nodo aggiunge un elemento alla sua memoria, dice agli altri nodi di fare altrettanto, per mantenere tutti la memoria con gli stessi elementi.
    La mia difficoltà consiste in questo:
    il metodo che devo realizzare è

    codice:
    void wait( String variabile , int valore ) throws InterruptedException,
    è richiede questo comportamento: il nodo che esegue questo metodo, controlla se nella sua memoria è presenta la variabile, con quel valore associato. Nel caso non ci sia tale coppia, il metodo va in wait(), bloccandosi fino a che nella memoria non sarà presente quello che cercava.
    Il metodo l'ho implementato così:

    codice:
    synchronized public void wait(String var, int val) throws InterruptedException
    {
       for(int i=0; i<memElements.size(); i++)// scorro la lista
       {
           //se almeno uno dei 2 parametri è diverso da ogni elemento nella lista
           
           while(memElements.get(i).getVar() != var || memElements.get(i).getVal() != val)
           {
               try
               {
                  wait();
               } catch(InterruptedException e) 
               {
                   
               }
           }      
       }
    }
    Aggiungo sotto il metodo inserisci() che non so se può tornare utile per capire meglio la situazione:

    codice:
    synchronized public void inserisci( String variabile, int valore )
        {
            boolean exit = false;
            for(int i=0; i<memElements.size() && !exit; i++)// scorro la lista
            {
                if(memElements.get(i).getVar() == var)// guardo se c'è quella variabile
                {
                    memElements.get(i).setVal(val);// se c'è, imposto il nuovo valore
                    notifyAll();//per chi è in Wait
                    exit = true;// posso uscire dal ciclo
                }      
            }
            if(!exit)//se non c'è già, exit è false
            {
                memElements.addFirst(new Element(var,val));// metto in testa il nuovo elemento
                notifyAll();//per chi è in Wait
            }        
        }
    La difficoltà che trovo sta nel fatto che il nodo che va in wait(), quando viene risvegliato da chi fa notifyAll, comunque per come è messo il codice non uscirà mai più dal ciclo while che lo rimette ogni volta in wait. Il fatto è che lui e solo lui può mettere nella sua memoria il nuovo valore comunicatogli da un altro nodo, ma per fare una inserisci() deve prima uscire dal metodo dell'attesa, modificare poi la memoria e quindi ha anche lui un nuovo elemento su cui fare un controllo per vedere se è ciò che cerca e poi eventualmente bloccarsi.
    Non ho idea di come implementare questo metodo, mi sapete dare qualche consiglio?
    Grazie mille

  2. #2
    Il tuo programma non esce dal ciclo while perché i valori che l'altro thread inserisce sono memorizzati si nella Collection, ma non nell'oggetto che è attualmente scandito dal ciclo for e che usi quindi nel controllo del while.

    Il while quindi sta verificando tutto un altro valore. Per ottenere ciò che vuoi dovresti effettuare una ricerca di quella coppia ogni volta esci dal wait(). Se la ricerca da esito positivo allora esci dal while, altrimenti ritorni in attesa.

    Nella collection che usi potresti avere un metodo contains() che ti permette di verificare se l'oggetto è presente o meno, ma ricordati di fare l'override del metodo equals() nell'oggetto che rappresenta la coppia.

    ciaoo

  3. #3
    Utente di HTML.it
    Registrato dal
    Sep 2004
    Messaggi
    143
    Ciao, grazie per la risposta.
    Purtroppo o non ho ben capito i tuoi consigli oppure non ho illustrato bene la situazione.
    Faccio un esempio pratico:
    mettiamo conto che io abbia 2 nodi, NodoA e NodoB, con al loro interno la memoria, quindi memoriaA e memoriaB.
    Ipotizziamo che a run-time nelle 2 memorie ci sia solo una coppia variabile-valore, a-1. Poi ad un certo punto su NodoB viene invocato wait( b , 2 ). Non c'è, per cui il NodoB va in wait().
    Dopo poco su NodoA viene invocato insert( b , 2 ). Appena NodoB ha messo la nuova coppia sulla sua memoria, dice agli altri Nodi di inserire anche loro b-2 nella loro memoria locale.
    NodoA farà una notifyAll per svegliare eventuali Nodi in wait(), e nel nostro caso c'è proprio NodoB in wait(), che per fare insert( b , 2 ) deve per forza essere risvegliato, solo che appena risvegliato controlla con

    codice:
    while(memElements.get(i).getVar() != var || memElements.get(i).getVal() != val)
    se la coppia che cerca adesso c'è, ma non potrà mai esserci, perché non è in grado di fare mai una insert(), non ne avrà modo, perché entrato nel metodo wait(b,2) non esce più, per uscirne ha bisogno di aggiornare la sua memoria, per aggiornare la sua memoria haa bisogno di uscire da wait(b,2).

    La situazione è più o meno questa, mi scuso se non ho capito i tuoi consigli, ma mi pare siano un pò differenti da ciò che ho bisogno.
    Grazie

  4. #4
    Scusami avevo inteso che la memoria fosse condivisa!!!

    però c'è una cosa che sicuramente non va e un'altra che invece non mi è chiara.

    Quello che non va è il ciclo while all'interno del for. con questo codice il tuo metodo si mette in wait ad ogni elemento della sua memoria che sia diverso dai valori che cerchi. (in pratica non uscirai mai). per evitare questo devi fare :

    codice:
    for(int i=0; i<memElements.size(); i++)// scorro la lista
       {
            "se memElements[i].var == var e memElements[i].val == val allora return"
        }
    
    wait();
    In pratica il wait deve essere eseguito solo se in tutto l'array la coppia non esiste.

    Quello che non mi è chiaro è :
    In che modo il NodoA comunica agli altri di inserire la coppia?

    Cioè da come ho capito io tu notifichi di aver inserito la coppia con una notifyAll, ma questo non ti assicura di inserire il valore corretto in tutti i nodi.
    Infatti con notifyAll tu non puoi specificare quale coppia hai inserito. Ad esempio supponi che il nodoB ha chiamato wait(C, 3) mentre il nodo A chiama insert(B,2) e poi notifyAll(). Questo sveglierà il nodoB che non sa che è stato inserito B-2 ma sa soltato hce è stata inserita una qualunque coppia. Non potendo sapere quale coppia è stata inseirta non può neppure sapere quando uscire dal wait.
    Tra l'altro se ad esempio il NodoC non è in wait non saprà neppure che è stato inserito un elemento.

    Pertanto hai bisogno di un sistema che comunichi a tutti i nodi quale coppia hai inserito e non soltanto che ne è stata inserita una.

  5. #5
    Utente di HTML.it
    Registrato dal
    Sep 2004
    Messaggi
    143
    Ciao!
    Hai perfettamente ragione, ho fatto i controlli nel ciclo for che facevano pena

    Dunque, per la parte che non è chiara. In effetti me ne sono un po fregato di spiegare come funziona la comunicazione tra i nodi; essendo come un sistema distribuito, c'è un gestore di comunicazioni che usa i Buffer, Socket ecc..., e fornisce i metodi read() e send() per far comunicare appunto i nodi.

    Se nodoA inserisce (c-3) poi fa un invio agli altri, con un pacchetto apposito per viaggiare nel sistema della gestione della comunicazione; tutti i nodi, e quindi anche gli altri che devono essere avvertiti che nodoA ha inserito, hanno un inner thread in ascolto, per vedere se arrivano richieste di vario tipo, come per esempio appunto di aggiornare la memoria con una nuova coppia.
    Non so se sono stato chiaro.

    In effetti continuando a riflettere su questo problema avevo pensato che potrei risolvere così:
    La classe Nodo, ogni volta che chiama un metodo, per esempio inserisci(.......), poi invoca la classe Memoria che è quella che lavora direttamente sulla struttura dati List che uso per memorizzare le coppie.
    Potrei passare alla classe Memoria, per mezzo del costruttore, proprio il gestore della comunicazione, che per ora non ha, non avevo avuto necessità di passarglielo per ora...
    Allora se un nodo fa notifyAll, gli faccio inviare l'aggiornamento agli altri nodi, che farei stare in attesa dopo wait():

    codice:
    ...
    ...
    wait();
    comunicazione.read();
    ...
    ...
    Siccome la read è bloccante, finchè non ricevono stanno ad attendere che arrivi li pacchetto,
    poi potrei fargli fare la insert() se il pacchetto è del tipo che lo richiede, tanto è un metodo che è appunto dentro la classe Memoria, in questo caso sarebbe una chiamata diretta tra metodi della stessa classe invece che passare dalla classe delegatrice Nodo.

    Il problema casomai a questo punto, sempre che la mia idea sia buona, si sposta al dover ricontrollare se la coppia inserita è ciò che il nodo aspettava, altrimenti deve tornare in wait().
    Posso invocare dentro wait(variabile , valore) se stessa, facendolo ricorsivo?

    codice:
    public void wait(variabile, valore)
    {
        for(int i=0; i<memElements.size(); i++)// scorro la lista
       {
            "se memElements[i].var == var e memElements[i].val == val allora return"
        }
    
        wait();
        comunicazione.read();
    
        .....controlli vari........
       
        wait(variabile, valore);//ricorsione
    
    }
    Se non penso male, dopo che qualcuno fa notifyAll chi era in wait() esegue l'istruzione appena dopo, per cui forse torna, se non ho trascurato qualche cosa.
    Che mi dite?


  6. #6
    L'idea di mettere insieme la memoria e il gestore delle comunicazioni non è molto pulita da un punto di vista logico, in quanto sono due componenti che dovrebbero rimanere separati.
    è piu corretto che il gestore delle comunicazioni restituisca la coppia al nodo e quest'ultimo comunichi alla memoria di inserire la coppia.

    Per quant origuarda la soluzione ricorsiva non te la consiglio, è molto piu semplice con un while.

    codice:
    while (non_è_lui) {
        wait();
        coppia=comunicazione.read();
        if (coppia.equals(quella che cerchi) {
            non è lui = false;
        }
    }
    Un'altra cosa, hai considerato cosa fare quando un nodo inserisce una coppia mentre l'altro nodo non è in wait? In questo caso penso che il listener debba comunque comunicare la coppia al nodo che provvederà a inseirre in memoria.

  7. #7
    Utente di HTML.it
    Registrato dal
    Sep 2004
    Messaggi
    143
    Ciao!
    Si è vero, non tenere ben separati gestore della comunicazione e nodo non è del tutto corretto, solo che non mi risulta facile pensare qualcosa di più corretto che porterebbe il metodo wait(variabile,valore) a dover in qualche modo ridare il controllo alla classe chiamante, cioè Nodo, che poi si occuperà dell'inserimento, chiamando il metodo insert() sempre della classe che gestisce in modo diretto la memoria. Mi viene da pensare magari di realizzare delle Exception mie per comunicare tra classi, ma, così a grandi linee, come idea, poi nello specifico ci dovrei pensare, anche perché le signature dei metodi non le posso cambiare, sono nelle specifiche del progetto, quindi ho pure questo vincolo.

    La soluzione al posto della ricorsione mi pare chiara, sicuramente migliore, thanks

    Si ho pensato all'inserimento distribuito anche se non c'è nessuno in wait(), diciamo che è stato il primo metodo che ho cercato di far funzionare, il resto va costruito intorno a quello. Pare funzioni perché alla fine stampo il contenuto di tutte le memorie locali e sono identiche.

    Procedo molto a rilento per colpa di un altro esame, ti ringrazio comunque per gli spunti che mi stai dando per procedere.

  8. #8
    Figurati!!!

    Il concetto di Exception è usato per comunicare situazioni di errore all'interno del programma che non possono essere gestite all'interno del metodo che la lancia, quindi non è consigliabile usarle per la normale logica esecutiva. per quest'ultima meglio usare i valori di ritorno dei metodi, o altri sistemi, ma non le eccezioni.

    Piuttosto per il problema di far sapere al nodo quando deve inserire in memoria, mi sa che è automaticamente risolto nel momento in cui la wait(nome,valore) ritorna.
    Infatti questo metodo è chiamato dal nodo, e il nodo sa su quale coppia ha chiamato la wait. Nel momento in cui wait ritorna vuol dire che il valore è presente nella memoria di un altro nodo e quindi va inserito, per cui il nodo chiamerà insert nella memoria.

    ciaoo

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.