430 likes | 565 Views
Progetto attori. Descrizione. Il sistema studiato e proposto simula la gestione di una stazione in cui pervengono richieste da parte di taxi e Utenti Gli utenti chiedono alla stazione la diponibilità di un taxi I taxi notificano alla stazione la loro diponibilità
E N D
Descrizione • Il sistema studiato e proposto simula la gestione di una stazione in cui pervengono richieste da parte di taxi e Utenti • Gli utenti chiedono alla stazione la diponibilità di un taxi • I taxi notificano alla stazione la loro diponibilità • La stazione gestisce l’assegnazione taxi utente.
Utente • L’utente arriva nella stazione • E si trova nello stato Arrivato in Stazione • L’utente invia la richiesta di un taxi • L’utente si mette in attesa di una riposta alla sua richiesta Wait • L’utente riceve la risposta in cui gli viene assegnato un taxi • L’utente prende il taxi e inizia il viaggio • Il viaggio termina in con l’arrivo nella stazione di destinazi0ne
Taxi • Il Taxi arriva nella stazione • E si trova nello stato Arrivato in Stazione • Il taxi aspetta la notifica di una richiesta dalla stazione • Il taxi si mette in attesa di una riposta alla sua richiesta Wait • Il taxi riceve la risposta in cui gli viene assegnato un utente • Il taxi prende l’utente e inizia il viaggio • Il viaggio termina in con l’arrivo nella stazione di destinazi0ne
Stazione • Stazione attende e gestisce le richieste provenienti dagli utenti e dai taxi utenti e taxi. • La gestione consiste nell’assegnare ad un utente un taxi. • La stazione funge da strumento di sincronizzazione per le entità presenti nel sistema.
Modellazione Petri Net • La stazione presenta due transazioni che rappresentano l’evento di arrivo in stazione • Le transazioni sono collegate a due post (taxi disponibili utenti disponibili) in cui le risorse rappresentano gli utenti e i taxi del sistema • I post taxi disponibili utenti disponibili sono legati alla transazione assegnamento permette la sincronizzazione. • La transazione assegnamento risulta collegata al post pronti a partire • Che sblocca la transazione su utenti e taxi Pronti a partire. • Le transazioni pronti a partire portano sia l’utente che i taxi nel post viaggio. • Terminato il viaggio l’utente e il taxi scelgono la stazione a cui arrivare riportano utente e taxi nei loro stati iniziali dai quali possono fare una nuova richiesta alla stazione.
Gestione dell’attesa • Il viaggio dura un certo tempo questo non e stato riportato nella Petri net iniziale e lo si riposta qui.
Modellazione Attori • Dalla descrizione del sistema si evince la presenza di tre attori. • Stazione • Taxi • Utente
Modellazione Attori • Dal grafico qui mostrato si evince che per ognuno degli attori del sistema vi è una classe che estende la classe Actor che ne specifica il comportamento. • Gli attori al loro interno sono modellati come degli automi a stati finiti e comunicano tra di loro mediante lo scambio di messaggi. • Lo scambio di messaggi è gestito da una macchina di controllo da noi implementata sulle specifiche di una simultedcontrolmachine presentata al corso.
Attore protectedvoidbecome( int status ){ this.status=status; } public abstractvoidhandler( Message m ); public abstractStringgetActorTypeAndID(); public staticvoidsetControlMachine( ControlMachine cm ){ Actor.cm=cm; } } public abstractclassActor { private staticControlMachine cm; private int status; public long now(){ returncm.now(); } public voidsend( Message m ){ cm.schedule(m); } public intcurrentStatus() { return status; }
Utente • public class Utente extendsActor{ • private staticfinalint INSTAZIONE = 0, INVIAGGIO = 1; • private Stazione stazioneCorrente; • private intid; • private intcomunicazioniTaxiNonDisponibiliConsecutive = 0; • private GuiAttorigui; • public Utente(Stazione stazioneCorrente, intid, GuiAttorigui) { • this(stazioneCorrente, id); • this.gui = gui; • } • public Utente(Stazione stazioneIniziale, intid){ • this.stazioneCorrente = stazioneIniziale; • this.id = id; • become(INSTAZIONE); • //primo messaggio per "muoversi dalla stazione" • //l'utente consuma tempo nella stazione e poi si muoverà dopo un certo tempo. • long tempoAttesa = now() + ScenarioData.TEMPO_CONSUMATO_IN_STAZIONE_MININO_DaUTENTE + • ScenarioData.RANDOM.nextInt(ScenarioData.VARIAZIONE_TEMPO_IN_STAZIONE_UTENTE); • send( newScegliTaxiPerViaggio( this, stazioneCorrente, tempoAttesa) ); • System.out.println(getActorTypeAndID() + • " invio:ScegliTaxiPerViaggio ricevente:" + stazioneCorrente.getActorTypeAndID() ); • } • public intgetID(){ • returnthis.id; • } • private voidimpostaStazione(Stazione stazione){ • stazioneCorrente = stazione; • } • //quando un utente lascia la stazione • private voidlasciaStazione(){ • stazioneCorrente = null; • } • public booleaneInStazione(){ • returnstazioneCorrente != null; • }
Utente • @Override • public voidhandler(Message m) { • if (currentStatus()==INSTAZIONE){ • if (m instanceofRispostaSceltaTaxi){ • System.out.println(getActorTypeAndID() + " elaboro rispostaSceltaTaxi"); • RispostaSceltaTaximsg= (RispostaSceltaTaxi)m; • //sceglie un taxi • LinkedList<Taxi> listaTaxi = msg.getTaxiInAttesaInStazione(); • Taxi taxiScelto = listaTaxi.get(ScenarioData.RANDOM.nextInt(listaTaxi.size())); • send(newSceltaTaxiEffettuata(this, stazioneCorrente, now() +1 /*piccoloritardo*/, taxiScelto)); • System.out.println(getActorTypeAndID() + • " invio:SceltaTaxiEffettuata ricevente:" + stazioneCorrente.getActorTypeAndID() + • " argomento:" + taxiScelto.getActorTypeAndID()); • } • if (m instanceofTaxiNonDisponibile){ • System.out.println(getActorTypeAndID() + " elaboro TaxiNonDisponibile"); • //il taxi non è disponibile, l'utente riprova a fare un'altra scelta da capo • comunicazioniTaxiNonDisponibiliConsecutive++; • if (comunicazioniTaxiNonDisponibiliConsecutive > 6){ • //se superiamo 2^6 limitiamo l'attesa tra due richieste a 2^6 • comunicazioniTaxiNonDisponibiliConsecutive = 6; • } • send( newScegliTaxiPerViaggio( this, stazioneCorrente, • now() + (int)Math.pow(2, comunicazioniTaxiNonDisponibiliConsecutive) )); • //ritardi esponenzialmente crescenti. • System.out.println(getActorTypeAndID() + • " invio:ScegliTaxiPerViaggio ricevente:" + stazioneCorrente.getActorTypeAndID() + • " tempo di scelta:" + (now() + (int)Math.pow(2, comunicazioniTaxiNonDisponibiliConsecutive))); • }
Utente • if (m instanceofAssegnazioneTaxi){ • System.out.println(getActorTypeAndID() + " elaboro AssegnazioneTaxi"); • //il taxi è stato assegnato all'utente. L'utente comunica la stazione al taxi che lo porterà • //in quella stazione. • comunicazioniTaxiNonDisponibiliConsecutive = 0; //reset • //sceglie una stazione • Stazione prossimaStazione; • intpos; • do { //evitiamo di scegliere la stazione corrente • pos = ScenarioData.RANDOM.nextInt(ScenarioData.stazioniDisponibili.length); • prossimaStazione = ScenarioData.stazioniDisponibili[pos]; • } while (prossimaStazione.equals(stazioneCorrente)); • //scelta la stazione si manda la comunicazione • AssegnazioneTaximsg = (AssegnazioneTaxi)m; • System.out.println(getActorTypeAndID() + " lascia la stazione:" + stazioneCorrente.getActorTypeAndID()); • send(newIndicazioniDiViaggio(this, msg.getTaxiScelto(), now(), prossimaStazione)); • System.out.println(getActorTypeAndID() + • " invio:IndicazioniDiViaggio ricevente:" + msg.getTaxiScelto().getActorTypeAndID() + • " argomento:" + prossimaStazione.getActorTypeAndID()); • //mi serve per il printline • Stazione oldstation=stazioneCorrente; • stazioneCorrente = prossimaStazione; • //si aggiorna lo stato • become(INVIAGGIO); • //update grafica • gui.aggiungiUtenteTransito(getActorTypeAndID(), " lascia la stazione:" + oldstation.getActorTypeAndID()+" in viaggio per "+prossimaStazione.getActorTypeAndID() ); • System.out.println(getActorTypeAndID() + " cambio stato: INVIAGGIO"); • } • }
Utente • if (currentStatus() == INVIAGGIO){ • if (m instanceofFineViaggio){ • System.out.println(getActorTypeAndID() + " elaboro FineViaggio"); • //l'utente è arrivato in stazione • //quindi consuma tempo nella stazione e poi si prepara per ripartire • long tempoAttesa = now() + ScenarioData.TEMPO_CONSUMATO_IN_STAZIONE_MININO_DaUTENTE + • ScenarioData.RANDOM.nextInt(ScenarioData.VARIAZIONE_TEMPO_IN_STAZIONE_UTENTE); • send( newScegliTaxiPerViaggio( this, stazioneCorrente, tempoAttesa) ); • System.out.println(getActorTypeAndID() + • " invio:ScegliTaxiPerViaggio ricevente:" + stazioneCorrente.getActorTypeAndID() ); • gui.rimuoviUtenteTransito(getActorTypeAndID()); • become(INSTAZIONE); • System.out.println(getActorTypeAndID() + " cambio stato: INSTAZIONE"); • } • } • } • @Override • public StringgetActorTypeAndID() { • return "UtenteID:" + id; • } • @Override • public booleanequals(Objectobj) { • if (objinstanceof Utente){ • return ((Utente)obj).getID() == this.id; • } • return false; • } • }//class
Taxi • public class Taxi extendsActor{ • private intid; //taxi id • public Taxi(Stazione stazioneIniziale, intid){ • this.id = id; • //il taxi si sposta in una stazione iniziale • send(newFineViaggio(this, stazioneIniziale, now(), null)); • System.out.println(getActorTypeAndID() • + " invio:FineViaggio ricevente:" + stazioneIniziale.getActorTypeAndID() • + " argomento: vuoto"); • } • public intgetID(){ • returnthis.id; • } • @Override • public voidhandler(Message m) { • if (m instanceofIndicazioniDiViaggio){ • System.out.println(getActorTypeAndID() + " elaboro IndicazioniDiViaggio"); • //il taxi è stato scelto ed ora si mette in viaggio con un utente • IndicazioniDiViaggiomsg = (IndicazioniDiViaggio)m; • long tempoTrascorso = now() + ScenarioData.TEMPO_MINIMO_CONSUMATO_IN_VIAGGIO + • ScenarioData.RANDOM.nextInt(ScenarioData.VARIAZIONE_TEMPO_IN_VIAGGIO); • //inviamo il messaggio di arrivo alla stazione
Taxi • send(newFineViaggio(this, msg.getStazione(), tempoTrascorso, (Utente)msg.getSender())); • System.out.println(getActorTypeAndID() • + " invio:FineViaggio ricevente:" + msg.getStazione().getActorTypeAndID() • + " argomento:" + msg.getSender().getActorTypeAndID()); • //e pure all'utente nel taxi • send(newFineViaggio(null, msg.getSender(), tempoTrascorso, null)); • System.out.println(getActorTypeAndID() • + " invio:FineViaggio ricevente:" + msg.getSender().getActorTypeAndID() • + " argomento: nessuno" ); • } • } • @Override • public StringgetActorTypeAndID() { • return "TaxiID:" + id; • } • @Override • public booleanequals(Objectobj) { • if (objinstanceof Taxi){ • returnthis.id == ((Taxi)obj).getID(); • } • return false; • } • }//class
Stazione • public class Stazione extendsActor{ • private GuiAttorigui; • private intid; • private LinkedList<Taxi> taxiInAttesa = newLinkedList<Taxi>(); • private LinkedList<Utente> utentiInAttesa = newLinkedList<Utente>(); • public Stazione(GuiAttorigui, intid) { • this.gui = gui; • this.id = id; • gui.aggiornaStazione(getActorTypeAndID(), 0, 0); • } • public Stazione(intid){ • this.id = id; • } • public intgetID(){ • returnthis.id; • } • public intgetUtentiAttesaSize(){ • returnutentiInAttesa.size(); • } • public intgetTaxiInAttesaSize(){ • returntaxiInAttesa.size(); • }
Stazione public voidhandler(Message m) { if (m instanceofScegliTaxiPerViaggio){ System.out.println(getActorTypeAndID() + " elaboro ScegliTaxiPerViaggio"); Utente richiedente = (Utente)m.getSender(); if (! utentiInAttesa.contains(richiedente)){ utentiInAttesa.addLast(richiedente); System.out.println("Aggiunto a:" + getActorTypeAndID() + " l'entità " + richiedente.getActorTypeAndID()); } if (taxiInAttesa.size() > 0){ //se c'è qualche taxi in attesa send(newRispostaSceltaTaxi(richiedente, now()+1 /*piccoloritardo*/, taxiInAttesa)); System.out.println(getActorTypeAndID() + " invio:RispostaSceltaTaxi ricevente:" + m.getSender().getActorTypeAndID() + " argomento:ListaTaxiInAttesa"); } else { send(newTaxiNonDisponibile(richiedente, now()+1)); //sempre piccoli ritardi System.out.println(getActorTypeAndID() + " invio:TaxiNonDisponibile ricevente:" + m.getSender().getActorTypeAndID()); } }
Stazione if (m instanceofSceltaTaxiEffettuata){ System.out.println(getActorTypeAndID() + " elaboro SceltaTaxiEffettuata"); //l'utente ha scelto un taxi e si verifica se è disponibile //o è stato preso nel frattemo della scelta. SceltaTaxiEffettuatamsg = (SceltaTaxiEffettuata)m; booleantaxiPresente = taxiInAttesa.remove(msg.getTaxiScelto()); if (!taxiPresente){ //se il taxi non c'è si avvisa l'utente send(newTaxiNonDisponibile(msg.getSender(), now()+1)); //sempre piccoli ritardi System.out.println(getActorTypeAndID() + " invio:TaxiNonDisponibile ricevente:" + m.getSender().getActorTypeAndID()); } else{ //il taxi è stato rimosso quindi c'è //l'utente si sposta. utentiInAttesa.remove((Utente)msg.getSender()); send(newAssegnazioneTaxi(msg.getSender(), now() /*immediato*/ , msg.getTaxiScelto())); System.out.println(getActorTypeAndID() + " invio:AssegnazioneTaxi ricevente:" + m.getSender().getActorTypeAndID() + " argomento:" +msg.getTaxiScelto().getActorTypeAndID()); } }
Stazione if (m instanceofFineViaggio){ System.out.println(getActorTypeAndID() + " elaboro FineViaggio"); //un utente ed un taxi sono arrivati FineViaggiomsg = (FineViaggio)m; //aggiorna le liste Utente utenteArrivato = msg.getUtente(); if (utenteArrivato != null){ //potrebbe essere che solo un taxi è arrivato (allo start) quindi //il carico è null utentiInAttesa.addLast(utenteArrivato); System.out.println("Aggiunto a:" + getActorTypeAndID() + " l'entità " + utenteArrivato.getActorTypeAndID()); } taxiInAttesa.addLast((Taxi)msg.getSender()); System.out.println("Aggiunto a:" + getActorTypeAndID() + " l'entità " + msg.getSender().getActorTypeAndID()); } gui.aggiornaStazione(getActorTypeAndID(), utentiInAttesa.size(), taxiInAttesa.size()); } @Override public StringgetActorTypeAndID() { return "StazioneID:" + id; } }//class
Controlmachine else if (m.getTime() == message.getTime()){ //se il tempo è uguale risolviamo con la monetina if (ScenarioData.RANDOM.nextBoolean()){ //50% di probabilità addFirst = true; } } if (addFirst){ //se è un evento che accadrà prima //si torna prima di questo elemento it.previous(); //e poi si aggiunge it.add(m); //si esce return; } } //se arriviamo qui o la coda e vuota o non abbiamo //inserito l'elemento prima di altri elementi events.addLast(m); } public classTimedSimulationextendsControlMachine{ private LinkedList<Message> events = newLinkedList<Message>(); private long time = 0; //tempo iniziale della simulazione private long maxSimulatedTime; //tempo massimo della simulazione. public TimedSimulation(long maxSimulatedTime){ this.maxSimulatedTime = maxSimulatedTime; } @Override public voidschedule(Message m) { //inseriamo opportunamente il messaggio in lista //System.out.println("nuovo messaggio in queue, siamo al tempo:" + time); //se la coda è vuota il for non sarà mai eseguito! for (ListIterator<Message> it = events.listIterator(); it.hasNext();) { //si scorrono i messaggi Messagemessage = it.next(); booleanaddFirst = false; if (m.getTime() < message.getTime()){ addFirst = true; }
Controlmachine • @Override • public voidunSchedule(Message m) { • //si gestisce il messaggio da elaborare • //si aggiorna il tempo della simulazione • time = m.getTime(); • // if (time % 100 == 0){ • System.out.println("time:" + time); • // } • //per verificare gli invarianti • int numeroTaxi=0; • int numeroUtenti=0; • for (int i=0; i<ScenarioData.NUMERO_STAZIONI; i++){ • numeroTaxi += ScenarioData.stazioniDisponibili[i].getTaxiInAttesaSize(); • numeroUtenti += ScenarioData.stazioniDisponibili[i].getUtentiAttesaSize(); • } • System.out.println("Utenti in stazione:" + numeroUtenti); • System.out.println("Taxi in stazione:" + numeroTaxi); • //si esegue il messaggio • m.getReceiver().handler(m); • }
Controlmachine • @Override • public void controller() { • System.out.println("Esecuzione avviata"); • while (time < maxSimulatedTime){ • //finchè il tempo della simulazione non è scaduto. Processa il messaggio in testa • if (events.size() > 0){ • unSchedule(events.removeFirst()); • } • else { • System.out.println("wtf!?"); • break; • } • } • } • @Override • public long now() { • returntime; • } • @Override • public void reset() { • //si resetta tutto • time = 0; • events = newLinkedList<Message>(); • } • // • }//class
Modellazione in Uppaal • Il sistema di sopra descritto è stato modellato utilizzando il formalismo dei Timed Automa. • Il sistema presenta anche in questo caso tre entità • La stazione che funge da controllore. • I taxi che offrono un servizio. • Gli utenti che richiedono un servizio.
Stazione Declaration • La stazione presenta delle variabili interne che mappano il numero di taxi presenti nella stazione e il gli id dei taxi presente nella stazione quest’ultima informazione viene mappata con un vettore booleano che ci informa se il taxi e presente o meno in stazione. • Vi sono inoltre due metodo che ci permettono di inizializzare e mantenere aggiornato questo vettore.
Utenti • L’utente presenta un clock tempo utente che tiene conto dello scorrere del tempo al suo interno usato soprattutto per computare la durata in attesa prima che gli venga inviata la lista dei taxi e la durata del viaggio. • Risulta chiaro che l’utente interagisce con la stazione per la gestione dell’assegnamento/scelta del taxi. • Per fare ciò usa dei canali di sincronizzazione che sbloccano attivano alcune transazioni condivise. • La scelta dell’ taxi viene fatta mediante l’uso di una struttura dati condivisa/globale (un vettore di interi) che traccia la posizione del Taxi.
Dichiarazioni Globali • Nel sistema considerato abbiamo visto che taxi e utenti interagiscono tra di loro e con la Stazione questo implica che una stazione può parale con tutti i taxi e con tutti gli utenti. Ricordado che la comunicazione è punto punto sono necessarie le seguenti matrici di canali. • chanchStation[numUtenti_t][numStazioni_t]; • chanchTaxiUtente[numUtenti_t][numTaxi_t]; • chanchTaxi[numTaxi_t][numStazioni_t]; • chanchNoTaxi[numUtenti_t][numStazioni_t];
Dichiarazioni Globali • Inoltre ci serve definire gli identificatori dei taxi all’intero di un range. • typedefint[0,NUMERO_TAXI-1] numTaxi_t; • typedefint[0,NUMERO_STAZIONI-1] numStazioni_t; • typedefint[0,NUMERO_UTENTI-1] numUtenti_t; • Inoltre come già anticipato in precedenza ci serve un vettore che mappa la posizione corrente del Taxi. • intsceltaStazioneByTaxi[NUMERO_TAXI];
Considerazioni • Il sistema cosi come è implementato presenta un problema di deadlock in quanto la scelta delle rotte assegnazione dei taxi e del tutto casuale. Questo potrebbe portare alla situazioni che vi è una stazione in cui troviamo utenti i taxi sono tutti in delle stazione e gli utenti nelle stazioni opposte. Inoltre si puo verificare starvation è possibile che i taxi non scelgano mai una stazione dove è presente un utente che aspetta. • Tutto questo può essere aggravato se il numero dei taxi è del tutto inferiore al numero delle stazioni.
Soluzione al problema. • Per garantire l’assenza di starvation e dead-look si è deciso di modificare la logica del taxi come segue. • Un taxi può restare inattivo in una stazione solo per un certo intervallo di tempo dopo di che sceglie una stazione da raggiungere. Sul come il taxi sceglie la stazione sta la strategia anti-deadlok e anti-stavation. • La strategia usata consiste nel far girare i taxi in tutte le stazioni in modo ordinato. Per fare questo è stato necessario modificare il taxi e la stazione.
Stazione / Taxi • Come si può osservare la stazione e il generico taxi presentano una piccola variante per la gestione del deadlock. Con questa modifica il sistema funziona anche in condizioni particolari in cui sono presenti molte stazioni molti utenti e pochi taxi. • La scelta della prossima stazione da visitare quando si lascia una stazione per lunga attesa è numStazioni_tstazioneDaVisitare(){ stazioneVisitare=(stazioneVisitare+1)%NUMERO_STAZIONI; returnstazioneVisitare; }