PRESENTAZIONE | SPECIFICHE | BILANCIAMENTO DEL CARICO | TOLLERANZA AI GUASTI | ANALISI DELLE PRESTAZIONI | METODO DI CALCOLO | CONCLUSIONI

DFGClient: DFGServer:

Per poter suddividere il calcolo di una immagine tra gli slaves, DFGServer deve mantenere una struttura dati (chiamata Tabella) in cui memorizzare gli slaves attualmente disponibili, la loro collocazione (nome dell'host e numero di porta) e la loro situazione di carico. Vedere la sezione Bilanciamento del carico per le specifiche relative alle modalità di scelta degli slaves da utilizzare.

DFGServer deve essere in grado di servire vari tipi di richieste. Ogni tipo di richiesta corrisponde ad un diverso tipo di Messaggio:

Operazioni svolte da DFGServer alla ricezione di un messaggio di tipo Messaggio_Mandelbrot:
Bisogna innanzitutto osservare che ogni messaggio di questo tipo contiene un elemento (ident) che lo identifica univocamente e il cui formato è "host_DFGClient : porta_DFGClient". Questa informazione è utilizzata solo per permettere il riconoscimento delle richieste di servizio per una loro eventuale interruzione.
Se non ci sono slaves disponibili, DFGServer comunica al client che il servizio non è attivo (chiudendo la connessione con esso). In caso contrario, si procede come segue:
Per prima cosa viene creato un oggetto GestoreRichiesta, che viene utilizzato per scandire la Tabella, crearne una copia contenente l'indicazione del numero di righe che ciascuno slave deve calcolare, allocare un'area di memoria per l'immagine, aggiornare la Tabella con la nuova situazione di carico e creare, per ogni slave, un thread Esecutore che si occupi di inviargli la richiesta e ricevere la corrispondente risposta.
I thread Esecutore vengono assegnati ad un gruppo di thread il cui nome identifica univocamente il servizio che stanno svolgendo (viene usato ident come nome per il gruppo) e viene dato loro un nome che permetta, in caso di necessità (ved. la gestione di una richiesta di interruzione), di ritrovare lo slave che devono contattare (il formato del loro nome è: "host_DFGSlave : porta_DFGSlave"). La figura seguente mostra un possibile schema dei gruppi di thread e dei thread in essi contenuti durante l'esecuzione di DFGServer:
Nel caso la richiesta vada a buon fine, ogni thread Esecutore ottiene la porzione di immagine che gli era stata commissionata e la memorizza nella posizione corretta dell'area di memoria appositamente predisposta dall'oggetto GestoreRichiesta che lo ha generato. Quando tutti i thread Esecutore hanno terminato il proprio compito, l'immagine ottenuta viene trasmessa al client.

Nota: il fatto di non realizzare GestoreRichiesta come thread (come si era fatto nelle versioni preliminari di DFG) ma solamente come oggetto di cui vengono invocati dei metodi introduce una serializzazione delle operazioni svolte da DFGServer, il quale non si mette in attesa di nuovi messaggi prima di aver creato tutti i thread Esecutore e aggiornato la Tabella. Questo permette di risolvere a priori possibili situazioni di corsa critica. Questa soluzione non provoca problemi di ritardo nel servizio, visto che le operazioni svolte tramite GestoreRichiesta sono tutte operazioni locali. Per lo stesso motivo, anche i thread GestoreInterruzione sono stati modificati nello stesso modo.

Operazioni svolte da DFGServer alla ricezione di un messaggio di tipo Messaggio_Interruzione:
In caso di interruzione volontaria del calcolo da parte dell'utente, si potrebbe semplicemente lasciar continuare calcolo dell'immagine da parte degli slaves, ignorandone la risposta. Questo approccio può però provocare un sovraccarico del sistema e si ritiene quindi oppurtuno che i DFGSlave interessati al calcolo dell'immagine vengano interrotti.
All'atto della ricezione di un Messaggio_Interruzione, viene creato un oggetto GestoreInterruzione che permette di estrarre dal messaggio un identificatore (ident) che corrisponde al lavoro da terminare e scandire la lista dei gruppi di thread presenti nel gruppo di thread principale (main), cercando il gruppo avente per nome ident. Questo gruppo contiene i thread Esecutore relativi al lavoro da terminare. Viene quindi creato, per ogni Esecutore trovato, un thread EsecutoreInterruzione che ha il compito di spedire allo slave corrispondente un Messaggio_Interruzione. I thread EsecutoreInterruzione vengono inseriti nel gruppo main.

Il procedimento di interruzione di un calcolo può essere realizzato in modi diversi da quello scelto (ad esempio riducendosi semplicemente a far terminare i thread Esecutore e GestoreMandelbrot coinvolti) . I pregi del metodo scelto sono la semplicità dei protocolli di comunicazione e la considerazione che la ricezione di un risultato (anche se parziale) del calcolo da parte di DFGClient è importante.
 
 
 

Esempio di risultato parziale del calcolo
Risultato parziale di un calcolo
Linea di comando: java dfg.dfg_server

DFGSlave:

DFGSlave deve essere in grado di servire due tipi di richieste. Ogni tipo di richiesta corrisponde ad un diverso tipo di Messaggio: Operazioni svolte da DFGSlave alla ricezione di un messaggio di tipo Messaggio_Mandelbrot:
Alla ricezione di una richiesta di questo tipo, DFGSlave crea un thread GestoreMandelbrot che si occupa di servirla; il thread estrae dalla richiesta i parametri, alloca un'area di memoria per l'immagine risultante e chiama la funzione nativa per il calcolo dell'immagine. Al thread viene assegnato come nome l'identificatore (ident) contenuto nel messaggio stesso (nota: il formato di ident non ha importanza, basta che permetta di identificare univocamente il lavoro che sta svolgendo). Questo è necessario per poter servire una eventuale richiesta di terminazione del calcolo proveniente da DFGServer. Il motivo della scelta di avere slaves concorrenti è determinato da due fattori: Operazioni svolte da DFGSlave alla ricezione di un messaggio di tipo Messaggio_Interruzione:
DFGSlave estrae dal messaggio il parametro ident e scandisce la lista dei thread contenuti nel gruppo main, uccidendo tutti i thread aventi per nome ident (è possibile che ci sia più di un thread chiamato ident se ci sono state ridistribuzioni di carico a seguito della caduta di uno o più slaves). Prima di terminare, ciascuno dei thread interessati spedisce il risultato parziale del calcolo a DFGServer. In questo modo, DFGClient riceve un'immagine incompleta ma che può ugualmente essere utile.
Nota: l'invio da parte di DFGClient di una richiesta di interruzione può (in casi molto particolari) aumentare il tempo di generazione di un'immagine. Ad esempio, se il messaggio di interruzione arriva a DFGSlave quando il calcolo è già stato completato ma prima (o durante) la spedizione a DFGServer del risultato, si interrompe la connessione tra DFGSlave e DFGServer e quindi si provoca una ridistribuzione di carico (e i nuovi slaves interessati non verranno interrotti). Per questo motivo si è prevista la possibilità di poter inviare più di una richiesta di interruzione da parte di DFGClient (anche se in pratica queste situazioni non si sono mai verificate).

Linea di comando: java dfg.dfg_slave porta_slave host_server carico_di_default



PRESENTAZIONE | SPECIFICHE | BILANCIAMENTO DEL CARICO | TOLLERANZA AI GUASTI | ANALISI DELLE PRESTAZIONI| METODO DI CALCOLO | CONCLUSIONI