Caricare documenti e articoli online 
INFtub.com è un sito progettato per cercare i documenti in vari tipi di file e il caricamento di articoli online.


 
Non ricordi la password?  ››  Iscriviti gratis
 

INTERAZIONE TRA I PROCESSI NEL MODELLO A SCAMBIO DI MESSAGGI

informatica



INTERAZIONE TRA I PROCESSI

NEL MODELLO A SCAMBIO DI MESSAGGI


Ricordiamo che in questo modello ciascun processo dispone della propria memoria locale, evolve in un ambiente proprio che non è comune ad altri processi. Ne segue che non è possibile che i processi entrino in competizioni su strutture dati condivise. Ne segue anche però che se due processi devono interagire, non possono più farlo tramite la memoria comune (per il semplice motivo che non esiste una memoria comune), ma possono farlo solo scambiandosi dei messaggi tramite il kernel del SO. Ogni volta che un processo desidera inviare un messaggio ad un altro processo, e ogni volta che un processo desidera ricevere un processo, essi devono fare una richiesta al kernel.

Un linguaggio di programmazione concorrente progettato per una macchina a memoria locale deve mettere a disposizione delle primitive  per lo scambio di messaggi. Ancora una volta, generalmente le primitive in questione sono soltanto due:



- una primitiva di invio send;

- una primitiva di ricezione receive.

Esisteranno una send a livello di linguaggio concorrente ed una send a livello di kernel; la prima send sarà più potente e più sofisticata, in quanto realizzata tramite opportuno uso di più send del livello kernel. Ugualmente dicasi per la receive.

Questo modello risulta particolarmente indicato per i sistemi distribuiti, più comunemente detti reti di calcolatori, ma è spesso usato anche con riferimento a macchine singole.

Le risorse sono sempre private rispetto a i singoli processi, e quindi se la natura del contesto impone che siano previste delle risorse comuni, esse potranno essere tali solo a livello logico, e non fisico. Nei fatti una risorsa appartiene ad un solo processo che nella fattispecie rappresenta il suo gestore. Il processo gestore di risorsa riceve, a mezzo del kernel, dei messaggi di richiesta, opera sulla risorsa di cui è proprietario e fornisce eventuali risposte. Quindi, mentre nel modello a memoria globale il gestore era una risorsa allocata staticamente e condivisa tra più processi, nel modello a memoria locale il gestore è un processo (ha quindi un carattere 'attivo', anziché 'passivo'), e poiché la sua ragione di essere è unicamente quella di servire le richieste di utilizzo da parte di altri processi esso viene detto processo servitore.


Cominciamo ora a prendere in considerazione alcuni tipi di primitive send & receive a livello di linguaggio. Al momento opportuno vedremo quali di esse corrispondono alla omonime primitive a livello kernel.

Le varie primitive send, receive si distinguono fra di loro per due motivi fondamentali:

- il modo in cui i meccanismi di trasmissione e ricezione si sincronizzano tra di loro utilizzando queste due primitive;

- il modo in cui vengono designati il processo destinatario della send ed il processo mittente della receive.

Queste differenziazioni d'altra parte possono riguardare solo i linguaggi, perché a livello kernel mittente & destinatario non possono che essere individuati mediante indirizzi di memoria (e si noti che possono essere indirizzi appartenenti all'area di memoria privata del mittente, all'area di memoria privata del destinatario o all'area di memoria propria del kernel); quanto alla sincronizzazione, per il kernel esisteranno solo i due tipi di sincronizzazioni più elementari possibili.



SINCRONIZZAZIONE TRA PROCESSI COMUNICANTI


Una comunicazione completa tra due processi può avvenire solo se vengono effettuate un send da parte del un mittente ed una receive da parte del destinatario.

La sincronizzazione delle operazioni in gioco in un simile fenomeno di comunicazione è legata alla semantica delle primitive. Si può distinguere come segue:


a) send asincrona;

b) send sincrona;

c) send di tipo chiamata di procedura remota;

d) receive bloccante;

e) receive non bloccante.


Passiamo ad esaminare nel dettaglio le cinque alternative.


A) SEND ASINCRONA Questo è il solo tipo di send messo a disposizione dai kernel dei SO, e di conseguenza tutte le altre si ottengono a partire da questa, con lo scopo di ottenere una più sofisticata tempificazione.

La sua caratteristica saliente è questa: il mittente continua nella propria esecuzione dopo avere inviato un messaggio.

La send effettuata dal mittente consiste in una chiamata al supervisore. Con la send vengono specificati due parametri: l'indirizzo del buffer della propria area memoria il cui contenuto deve essere inviato al destinatario, e l'identificatore del destinatario. A questo punto, il kernel accede all'area di memoria del mittente, copia il buffer indicato in un buffer della propria area dati, e restituisce il controllo al mittente. Il mittente riscontra che il proprio buffer è stato liberato, e dal suo punto di vista questo è il segno che l'operazione send è conclusa. Di conseguenza esso ridiventa running sul proprio processore virtuale [1].

Questa versione della send si dice asincrona perché in essa non è presente alcuna relazione tra stato del mittente e stato del destinatario; il mittente invia il suo messaggio senza preoccuparsi dello stato del destinatario; a tempo debito, il destinatario riceverà il messaggio senza interessarsi dello stato attuale del mittente.

Il suo vantaggio evidente è che essa permette il massimo del parallelismo, in quanto il mittente, una volta ricevuto indietro il controllo del proprio processore da parte del SO, è libero di proseguire nelle sue operazioni e non deve stare ad aspettare che il destinatario prelevi il messaggio. Tuttavia, questa send presenta anche molti svantaggi. Uno è che, trattandosi di un meccanismo di basso livello, cercare di realizzare schemi più complessi a partire da esso risulterebbe molto laborioso. Inoltre, almeno in linea teorica, il kernel dovrebbe avere un buffer illimitato, dato che, potenzialmente, il mittente potrebbe fare infinite send senza attendere alcuna receive.


B) SEND SINCRONA I parametri che devono essere specificati sono gli stessi del caso precedente.

Inoltre anche in questo caso quando il mittente esegue una send viene effettuata una system call e interviene il kernel del SO. A questo punto, si presentano due alternative:

1) il destinatario ha già eseguito una receive;

2) il destinatario non ha ancora eseguito la receive.

Nel secondo caso, il mittente viene sospeso finché il destinatario non effettua la receive. Dato che il mittente è sospeso, esso si trova 'con le mani legate' rispetto alla possibilità di inviare ulteriori messaggi e quindi non c'è necessità di svuotare il contenuto del buffer. Quando finalmente il destinatario fa la receive, il kernel copia il messaggio dall'area di memoria indicata nella send a quella indicata nella receive [2], e entrambi i processi ridiventano running ciascuno sul proprio processore virtuale.

Nel primo caso, invece, il mittente viene temporaneamente sospeso, ma poiché non si presenta nessun ostacolo l'operazione viene portata rapidamente a compimento con la liberazione dei due processi.

Succede comunque che quando il mittente ridiventa ready lo ridiventa sicuramente anche il destinatario, e questa doppia, simultanea transizione di stato è contrassegnata dall'avvenuto passaggio dell'informazione dall'area mittente all'area destinatario. La sincronizzazione è associata al fatto che i dati vengano fisicamente trasferiti fra le due aree, e quindi la proposizione 'messaggio ricevuto' esprime di fatto lo stato del processo mittente.

Ciò comporta anche che, diversamente dal caso precedente, il destinatario ha conoscenza dello stato del mittente, e inoltre non si pone il problema della lunghezza del buffer del kernel. Lo svantaggio più evidente è costituito dalla perdita di parallelismo, poiché il mittente deve stare ad aspettare che il destinatario abbia ricevuto il messaggio prima di riprendere il proprio lavoro.

La send sincrona può essere realizzata soltanto a partire da send asincrone e come tale è propria di linguaggi ad alto livello, e non dei kernel dei SO.


Riserviamoci di esaminare la prossima volta la send tipo chiamata di procedura.


D) RECEIVE BLOCCANTE. Anche la receive è una system call ed è caratterizzata dai seguenti parametri:

Receive (indirizzo del buffer del destinatario in cui il messaggio deve essere memorizzato; nome del mittente oppure della mail box).

Poiché più mittenti possono voler inviare messaggi ad uno stesso destinatario, può essere provveduto uno spazio apposito nell'area di memoria del kernel, che è la mail box del destinatario in questione, nella quale i messaggi in arrivo vengono sistemati in una coda.

Il destinatario che esegue una receive bloccante rimane bloccato fino a che non gli viene inviato un messaggio

Vediamo cosa succede se si accoppiano una receive bloccante con una send asincrona. Se viene eseguita prima la send asincrona, il messaggio viene depositato nel buffer del kernel; quando successivamente il destinatario eseguirà la receive non rimarrà bloccato, poiché risulterà effettivamente disponibile un messaggio. Se invece è la receive bloccante ad essere eseguita per prima, il destinatario rimarrà bloccato fino a che il mittente non effettuerà una send. A questo punto entrambi i processi verranno sbloccati. Avviene in effetti (ma solo in tale eventualità) la stessa cosa che accade per una send sincrona: il messaggio viene copiato direttamente dal buffer del mittente a quello del destinatario.

Se invece accoppiamo una receive bloccante con una send sincrona, la send causerà il blocco del mittente se eseguita prima della receive, mentre non lo causerà se eseguita dopo. Si noti tuttavia che in entrambi i casi i processi ripartono contemporaneamente, divenendo running si rispettivi processori virtuali.


E) RECEIVE NON BLOCCANTE. Quando viene eseguita, il ricevente non viene bloccato anche se non c'è nessun messaggio disponibile.

Questa receive serve per realizzare il cosiddetto POLLING. Supponiamo che un processo abbia la possibilità di attingere da più mailbox. In tal caso è evidente che deve essere usata una receive non bloccante, poiché non avrebbe senso che il destinatario rimanesse bloccato in attesa su di una mailbox quando in qualche altra potrebbe arrivare (o essere già arrivato) un messaggio.

Per esigenze di programmazione, però, potrebbe essere necessario fare in modo che un processo ricevente si blocchi in seguito ad una Receive e fino a quando non giunge un messaggio; per rendere possibile questa situazione nei SO che implementano la receive non bloccante, si fa così: il processo effettua la receive e se il risultato è negativo si mette in attesa su di un SEMAFORO TEMPORALE (un semaforo che automaticamente 'diventa verde' dopo un certo intervallo di tempo). Quando viene risvegliato, esso riesegue la receive non bloccante. La receive restituirà ogni volta un parametro di ritorno che dice se l'area buffer interpellata è piena o vuota.

Una receive non bloccante può essere accoppiata, come del resto accadeva per la bloccante, sia con una send asincrona che con una send sincrona. In questo secondo caso, se si esegue una receive quando non c'è nessun processo in attesa sulla send, il ricevente prosegue la sua esecuzione. Quando in seguito il mittente chiama la send, esso si blocca; non si tiene conto cioè della receive precedente, come se quest'ultima non fosse stata proprio eseguita, in quanto l'unica cosa che conta è se in questo momento il buffer del destinatario è disponibile a ricevere messaggi.


Ancora sulla SEND SINCRONA. Esclusivamente con riferimento a sistemi distribuiti su reti locali, quella che abbiamo chiamato send sincrona è ribattezzata send bloccante e viene soggetta alla seguente distinzione:

- send bloccante semplice;

- send bloccante sincrona.


Supponiamo di avere a che fare con una rete di elaboratori elettronici. Se avviene uno scambio tra un mittente ed un destinatario all'interno di una stessa macchina, e quindi nell'ambito di uno stesso SO, tutto procede come per la send sincrona descritta prima.


Se i processi mittente e destinatario si trovano invece su macchine differenti, la send provoca comunque un blocco del mittente, ma per un diverso motivo. Il mittente viene bloccato non fino a quando il messaggio viene copiato nel buffer del destinatario, ma fino a quando il messaggio viene consegnato ad una particolare routine del kernel, detta TRASMETTITORE, incaricata di provvedere alla trasmissione delle informazioni sulla rete.

In questo caso, dunque, bisogna aspettare semplicemente che sia libero il processo trasmettitore. Il messaggio viene allora prelevato dall'area di memoria del mittente e affidato al trasmettitore; il mittente viene immediatamente sbloccato.

Questa send è bloccante, ma semplice e non sincrona, poiché non è richiesto che il mittente attenda l'avvenuta ricezione del messaggio. D'altra parte ciò sarebbe non poco complicato; premesso che sulle due macchine risiederanno due diversi SO ciascuno con il proprio kernel, il mittente dovrebbe effettuare la sua send e mettersi in attesa; il kernel dovrebbe aspettare che il trasmettitore sia libero e trasmettere mediante esso il messaggio al kernel della macchina su cui c'è il processo destinatario. Questo secondo kernel dovrebbe a sua volta aspettare la receive da parte del destinatario; a questo punto avverrebbe la consegna del messaggio, e in più dovrebbe essere inviato un messaggio al kernel del processo mittente, che potrà essere così sbloccato.




Si ipotizza sempre di avere a che fare con sistemi a monoprocessore. Nei fatti, un processo che è running sul proprio processore virtuale è un processo ready, dato che ha bisogno solo della CPU per poter funzionare.

Non è specificato se tale trasferimento avvenga comunque tramite un buffer del kernel, cosa che sembra probabile.




Privacy




Articolo informazione


Hits: 3264
Apprezzato: scheda appunto

Commentare questo articolo:

Non sei registrato
Devi essere registrato per commentare

ISCRIVITI



Copiare il codice

nella pagina web del tuo sito.


Copyright InfTub.com 2024