|
Appunti informatica |
|
Visite: 1400 | Gradito: | [ Picolo appunti ] |
Leggi anche appunti:Il microprocessore: storia ed evoluzioneIl microprocessore: storia ed evoluzione Storia Il microprocessore nasce Manuale della difesaInterazioni tra processi e primitiva JoinInterazioni tra processi e primitiva Join Le interazioni tra processi |
GESTIONE DEI PROCESSI
Un PROCESSO, come abbiamo già avuto modo di dire, non è altro che un PROGRAMMA IN ESECUZIONE presso la CPU. Questo non vuol dire però che ad ogni 'colpo di clock' sia eseguita una sua istruzione, fino al completamento del programma stesso. Il programma può essere infatti interrotto in qualunque momento per lasciare spazio ad altre operazioni. È più corretto allora riguardare un processo come un programma del quale sia eseguita almeno una istruzione e che non sia ancora terminato.
Si può pensare ad un processo anche come ad una sequenza di istruzioni, con un suo inizio ed una sua fine, che fa parte di un programma più grande. Consideriamo un esempio significativo. È dato un programma il quale effettua la seguente operazione sequenziale: legge da un file, esegue le istruzioni in esso contenute e scrive il risultato su di un altro file. Il file è per noi un insieme ordinato di N record.
N-record ELABORAZIONE N-record
Il testo del programma in pascal-like è dunque il seguente.
var buffer : T ;
i : 1..N
begin
for i : = 1 to N do
begin
LETTURA (buffer) ;
ELABORAZIONE (buffer) ;
SCRITTURA (buffer) ;
end ;
end .
Nella sua interezza il programma può essere visto come un unico processo; ma esso può essere trattato anche come l'insieme di tre processi: lettura, elaborazione e scrittura, che cooperano o, come si dice nel gergo dei SO, concorrono ad ottenere il risultato finale. Vi sarà poi un'operazione di livello più basso che coordinerà i tre processi per ottenere la funzione desiderata a più alto livello (l'intero programma).
Nel primo caso il programma è scritto in modalità sequenziale, e "processo" è sinonimo di "programma" nel senso usuale del termine (una serie di linee di codice che svolgono una determinata funzione). Nel secondo, esso è scritto in modalità concorrente: vengono generati da un 'processo padre' tre 'processi figli' che cooperano. In tal caso per "processo" si può intendere perciò 'una parte', anziché 'il tutto'[1].
In tutti e due i casi il processo rappresenta comunque un'attività eseguibile dal processore: una sequenza di istruzioni, un insieme di dati su cui esse operano ed uno stack. Perché il SO possa gestire il processo, deve esistere un'area dati non accessibile al processo ma associata a quest'ultimo, contenente un insieme di informazioni indispensabili, detto DESCRITTORE DEL PROCESSO. Un processo non può esistere se non esiste il suo descrittore. Il descrittore di ogni processo risiede nel nucleo del SO.
Un processo nasce nel momento in cui viene allocato il suo descrittore, e quindi un attimo prima che venga eseguita la sua istruzione iniziale. Per tale ragione si può affermare che un processo 'prende vita' già prima di cominciare ad essere eseguito.
Con riferimento alla struttura presentata a pag.10, l'allocazione dei descrittori è rigorosamente STATICA. Il numero dei possibili descrittori è fisso, e il SO non deve fare altro che riempirli all'atto della creazione di nuovi processi. Se fosse vero il contrario (ossia se l'area di memoria per i descrittori fosse allocata al momento della creazione dei processi) il livello 6 dello schema dovrebbe seguire, anziché precedere, il livello 7. Non che ciò sia impossibile, ma nella pratica non avviene mai.
Il descrittore è un RECORD, ovvero un insieme di campi. Uno di essi contiene il nome del processo. Un secondo campo del descrittore conterrà l'insieme dei valori dei registri del processore nel momento in cui quest'ultimo perde temporaneamente l'usufrutto della CPU, ossia nel momento in cui passa dallo stato running allo stato ready. È possibile che lo stato[2] del processo (running, ready, wait) sia esplicitamente contenuto in un altro campo, ma più spesso questa informazione è implicita: se determinati processi sono in attesa del verificarsi di uno stesso evento, i rispettivi descrittori sono fra di loro linkati, il che indirettamente segnala il fatto che nessuno di essi è in esecuzione .
A questo proposito, va precisato che in realtà i possibili stati di un processo non sono tre, ma cinque: a quelli che già conosciamo devono essere aggiunti lo stato di ingresso (quello che si ha alla nascita del processo, ovvero un attimo prima che quest'ultimo divenga ready) e lo stato di uscita (quello che si ha tra l'esecuzione dell'ultima istruzione e il rilascio del descrittore del processo, ossia un attimo prima che il processo 'muoia'). Questi due stati sono caratterizzati dal fatto di essere assunti una sola volta, ma la loro esistenza è indispensabile perché essi delimitano i tempi entro i quali il descrittore del processo viene rispettivamente allocato e deallocato. Il seguente grafico riassume gli stati di un processo e la sequenza in cui possono verificarsi.
INGRESSO RUNNING
READY
USCITA
WAIT
I processi possono essere fra di loro in COMPETIZIONE, in COOPERAZIONE e in INTERFERENZA. Il SO deve mettere a disposizione strumenti per risolvere la competizione, permettere la cooperazione e proteggersi dalle interferenze. Si intuisce che la possibilità di fare concorrere, cioè cooperare, i processi, deve essere legata alla loro interdipendenza. In particolare se fra le azioni elaborative che si vorrebbero far concorrere esiste una relazione d'ordine totale il concetto di cooperazione viene a cadere, poiché tentare di farli cooperare non servirebbe a niente. Per trarre vantaggio dalla cooperazione, le azioni elaborative devono essere caratterizzate da un ordinamento parziale.
La competizione è una forma di interazione tra i processi prevedibile, ma non desiderata, perché rallenta l'esecuzione degli stessi. Viceversa la cooperazione è una forma di interazione prevista e desiderata, che avviene fra processi logicamente 'imparentati'. Un esempio di cooperazione è quello tra processi concorrenti che si scambiano messaggi di sincronizzazione che permettono di proseguire nella loro esecuzione. Un esempio di competizione è quello tra più processi che vogliono usare una singola stampante (non virtuale). Chi genera uno di questi processi deve prevedere la possibilità (ovviamente indesiderata) che vi possano essere altri processi concorrenti, i quali pure richiedano l'uso della stampante, e deve perciò fare in modo che tali conflitti, non certi, ma possibili, non blocchino il sistema. Il problema della competizione subentra solo quando si usano risorse comuni.
Un modo per risolvere il semplice problema di competizione che è stato presentato è il seguente. Diciamo p e q i due processi che richiedono l'uso della stampante. Il SO rende la stampante visibile solo ad un terzo processo, separato, di nome z, per cui p e q devono scambiare messaggi necessariamente con z se vogliono stampare. Quindi ad esempio p invia il testo che desidera stampare a z, e questo a sua volta genera il codice necessario per pilotare la stampante. Analogamente fa q. (In assenza del processo z, dovrebbero essere p e q a generare tale codice). Il processo z può agevolmente gestire la competizione inviando alla stampante un testo alla volta. Quindi un modo banale di procedere è quello di rendere invisibile la risorsa a tutti i processi che potrebbero richiederne l'uso, fuorché ad un singolo processo dedicato.
Quanto all'interferenza, essa si verifica in presenza di interazioni tra processi che la natura del problema non richiederebbe (ad es. il processo P ha bisogno di effettuare una stampa, ma prima che ciò avvenga un secondo processo Q altera senza alcuna necessità lo stato della stampante) o in caso di erronee soluzioni a problemi di cooperazione e competizione (ad es. P e Q sono due processi che possono effettuare una stampa una riga per volta in mutua esclusione; essi allora stampano ciascuno un proprio listato alternando una riga dell'uno e dell'altro: la stampa finale sarà ovviamente priva di significato). Il ruolo che ha il SO nel ripararsi dai suoi effetti è limitato. Il SO può occuparsi solo delle interferenze MACROSCOPICHE, mentre la maggioranza delle interferenze dovrebbero essere gestite a monte dal linguaggio di programmazione.
La possibilità di una programmazione concorrente è offerta dal fatto che è lecito, ad esempio, leggere l'i-esimo record mentre si scrive l'(i-1)-esimo. Non esiste dunque un ordinamento totale tra le 3*N operazioni coinvolte, ma solo parziale.
Lo 'stato' di un processo dal punto di vista del SO (detto anche macrostato) è concettualmente diverso dallo stato di avanzamento nell'esecuzione di un programma, ossia l'insieme delle variabili, dei dati e del PROGRAM COUNTER.
L'Ancilotti-Boari a pag.300-301 cita altri possibili campi del descrittore: se i processi vengono gestiti, come spesso accade, mediante una struttura FIFO (coda) ogni descrittore deve avere un campo puntatore al processo successivo. Se vengono gestiti con un sistema a priorità, sarà presente un campo 'modalità di servizio' contenente un'informazione che rappresenta la priorità di assegnazione della CPU del processo in esame rispetto agli altri.
Appunti su: |
|