• Non ci sono risultati.

Network C-Linda

2.4.2.3.3.3 L’ordinamento delle mosse

Tab 2.5b Suddivisione della partita in stadi Qual è l’identità dei termini citati?

3.3 Network C-Linda

C-Linda è un’istanza, un’implementazione reale del modello Linda. Esso risulta dalla integrazione del linguaggio sequenziale C con il linguaggio di coordinamento Linda. C-Linda è dunque un linguaggio di programmazione concorrente completo:

• Linda fornisce gli strumenti per cementare in un unico programma parallelo più computazioni indipendenti;

• C permette di programmare in sequenziale ciascun flusso separato di computazione.

3.3.1 Variazioni rispetto al modello

Il linguaggio di programmazione C-Linda implementa abbastanza fedelmente il modello Linda. In esso ritroviamo oggetti e strumenti oramai familiari: le tuple, lo spazio delle tuple e i quattro operatori di base: out, in, rd ed eval. Tuttavia incontriamo anche alcune novità rispetto alla definizione del modello formulata.

3.3.1.1 Gli operatori inp e rdp

È già stata sottolineata la proprietà dei costrutti in e rd di sospendere il processo che li esegue qualora non esista alcuna tupla corrispondente all’antitupla fornita loro in argomento. Il fatto che entrambi gli operatori destinati al recupero delle tuple presentino questa caratteristica può apparire una limitazione alla espressività del linguaggio.

Si supponga infatti di voler programmare la seguente situazione: un processo P deve eseguire il comando C1 se nello spazio delle tuple è presente la tupla t, il comando C2 altrimenti. Seppure non impossibile, descrivere questo scenario con i soli operatori Linda di base non è immediato ed intuitivo.

Quello di cui si avrebbe bisogno è la possibilità di testare la presenza o meno di una tupla nell’omonimo spazio. Per soddisfare questa esigenza C-Linda mette a disposizione due nuovi operatori: inp e rdp. Si tratta di varianti in forma di predicato

rispettivamente di in e rd. A differenza di quest’ultimi, però, inp e rdp non causano la sospensione del processo invocante in assenza della tupla cercata. Analizziamo in dettaglio gli effetti prodotti dalla loro esecuzione:

• argomento dei due operatori è una antitupla. Essi cercano di localizzare nello spazio delle tuple una tupla corrispondente ad essa;

• in caso di ricerca fallimentare viene ritornato il valore 0, altrimenti viene eseguito l’assegnamento attuali-formali e ritornato il valore 1 (nel caso di inp si ha anche la rimozione della tupla trovata).

L’utilizzo di questi operatori deve essere fatto con cautela poiché la loro efficienza è fortemente dipendente dall’implementazione reale. In alcune situazioni, in cui vi siano particolari esigenze riguardo le prestazioni dei programmi, è quindi preferibile

rinunciare a queste forme di predicato e ricorrere a tecniche alternative (uso di tuple contatore o tuple semaforo) [CarGel90].

Esempio 3.8

Si vuole fondare l’implementazione di un giocatore parallelo di scacchi sul modello master-worker. In una soluzione banale il processo master

distribuisce lavoro ai worker fino a che ve ne sono non occupati e di seguito si assegna lui stesso del lavoro. Completata la sua fase di calcolo esso controlla se vi sono dei risultati in arrivo dai worker, eventualmente li gestisce e successivamente

riesegue ciclicamente le operazioni descritte fino ad esaurimento dei lavori. In questo contesto emerge l’utilità dei nuovi operatori inp e rdp:

while (!fine_lavori()) {

while (!fine_lavori() && !rdp("worker_liberi,0)) distribuisci_un_lavoro(); if (!fine_lavori()) esegui_un_lavoro(); while (inp("risultato",?r)) gestisci_risultato(r); }

3.3.1.2 Campi formali anonimi

C-Linda permette di definire un campo formale di una antitupla come anonimo; ciò significa che a tale campo non è associata alcuna variabile. Un campo formale anonimo esprime la volontà di non conoscere il contenuto del campo corrispondente di una certa tupla. L’esecuzione dei comandi in(a) o rd(a) in cui l’antitupla a contiene un campo formale anonimo comporta infatti l’omissione dell’assegnamento attuale-formale per quel campo. Il vantaggio che deriva da questo meccanismo è duplice:

• sensibile risparmio in tempo di esecuzione nel caso di campi di grosse dimensioni

• risparmio di spazio e linee di codice per la

dichiarazione della variabile destinata alla ricezione del campo attuale della tupla che sarebbe altrimenti necessaria.

Esempio 3.9

In un programma parallelo basato sul paradigma master-worker talvolta accade che un lavoro L, decomposto in sottolavori affidati a processi worker, non sia più necessario (ad esempio per l’occorrere di un taglio in una visita alpha-beta di un albero di gioco)

rendendo così inutile l’esecuzione dei sottolavori. In questa eventualità il gestore del lavoro L deve rimuovere dalla lista dei lavori i sottolavori di L non ancora prelevati dai processi worker. In questa

operazione non è interessante il contenuto delle tuple rimosse: è quindi appropriato l’utilizzo di campi formali anonimi:

while (inp("sottolavoro_L",?struct descrizione_lavoro));

/* descrizione lavoro è un nome di tipo e non una variabile */

3.3.2 L’ambiente di programmazione

Un linguaggio di coordinamento supporta la creazione di processi e la loro interazione. Entrambi questi servizi sono di solito resi disponibili direttamente dal sistema operativo in una qualche forma accessibile al programmatore. Si potrebbe quindi evitare l’utilizzo di un linguaggio di coordinamento e fare affidamento sul sistema operativo quale supporto alla programmazione concorrente. Questa strategia è semplice, ma sfortunatamente primitiva. A differenza di una libreria di primitive del sistema operativo, un linguaggio di coordinamento è supportato da un

compilatore e da un ambiente di sviluppo e controllo dei programmi.

Il compilatore è il componente più importante del sistema C-Linda. È implementato come un pre-compilatore il quale trasforma le operazioni Linda in "normali" operazioni C ottenendo così un codice completamente in C che sarà successivamente tradotto dal compilatore standard di questo linguaggio.

Il compilatore C-Linda è ottimizzante, cioè mirato a tradurre i costrutti Linda in modo che la loro esecuzione sia efficiente. Vediamo un esempio di ottimizzazione volta a ridurre il tempo di ricerca di una tupla: tuple ed antituple sono

partizionate in classi di equivalenza in base alla loro struttura (numero, tipo e valore dei campi). In base a tale partizione tuple di una classe non possono corrispondere ad antituple di un’altra; in questo modo il numero di confronti che devono essere fatti per la ricerca di una tupla sono notevolmente ridotti, dato che la ricerca è limitata alle tuple di una sola classe di equivalenza e non all’intero spazio delle tuple. La creazione della partizione appena descritta è completamente a carico del compilatore Linda. L’implementazione del

modello Linda sarebbe improponibile in assenza di un compilatore ottimizzante dato il degrado delle prestazioni che ne deriverebbe [Lin90].

L’ambiente di programmazione C-Linda comprende anche un complesso ed efficace insieme di utilità per l’assistenza

del programmatore nello sviluppo e la correzione dei

programmi [CarGel90]. Alcuni di questi strumenti sono molto ad alto livello (Tuplescope); essi possono fornire, ad

esempio, una visualizzazione grafica degli oggetti (tuple) e degli agenti (processi) che compongono un programma Linda e descriverne dinamicamente l’evoluzione durante l’esecuzione.