Gestione dei processi

Transcript

Gestione dei processi
Gestione dei processi
Un processo è sostanzialmente un programma in esecuzione, per svolgere le funzioni
alle quali è preposto, il processo necessita determinate risorse, come tempo di
elaborazione, memoria, file e dispositivi I/O. Queste risorse si assegnano al processo
al momento della sua creazione o al momento della sua esecuzione. Il processo è
una unità di lavoro, ed esistono processi di sistema e processi utente, tutti questi
processi si possono eseguire in maniera concorrente.
Ogni processo nei moderni sistemi può essere suddiviso i diversi thread, ed il sistema
operativo ha il compito di gestire i processi e i thread di sistema e utente:
cancellazione e creazione, scheduling e gestione degli stalli. I primi sistemi di calcolo
consentivano l'esecuzione di un solo programma per volta, che aveva il controllo
completo di tutte le risorse del sistema. Gli attuali sistemi consentono che più
programmi siano caricati contemporaneamente in memoria ed eseguirli in modo
concorrente.
Processo
Un sistema a lotti (batch) esegue lavori(job), mentre un sistema a partizione del
tempo esegue programmi utenti(task). Un utente può eseguire più programmi alla
volta, anche se esegue l'utente una sola operazione per volta in realtà il SO deve
eseguire le proprie attività interne. Tali attività concorrenti sono simili per molti
aspetti l'une alle altre e sono denominate pertanto processi.
Informalmente un processo è un programma in esecuzione. Esso è qualcosa in più
del codice di un programma, sezione testo, comprende anche l'attività corrente,
rappresentata dal valore del contatore di programma e dal contenuto dei registri
della CPU, comprende anche la propria pila (stack), che contiene i dati temporanei, e
una sezione dati contenente le variabili globali. Il programma pertanto è un entità
passiva, una specie di resoconto dell'attività svolta dal processo, che appunto è un
entità attiva, con un contatore di programma (program counter) che tiene conto
delle prossima istruzione. Sebbene due processi possano essere associati allo stesso
programma sono tuttavia due sequenza di esecuzione distinte.
Stato di un processo
Mentre un processo in esecuzione è soggetto a cambiamenti di stato, ogni processo
può trovarsi in uno dei seguenti stati:
 Nuovo: si crea il processo
 Esecuzione: Vengono eseguite le istruzione del relativo programma
 Attesa: Il processo attende che si verifichi qualche evento (come il
completamento di un I/O o la ricezione di un input).
 Pronto: Il processo attende di essere assegnato all'unità di elaborazione.
 Terminato: Il processo ha terminato la sua esecuzione.
In ciascuna unità di elaborazione può essere in esecuzione solo un processo per
volta, sebbene molti processi possano essere pronti o nello spazio di attesa.
Descrittore di processo
Ogni processo nel SO è rappresentato da un descrittore di processo (PD) detto anche
blocco di controllo di un processo(PCB). In descrittore di processo contiene molte
informazioni connesse al processo tra cui:
 Stato del processo: lo stato può essere uno tra quelli elencati sopra.
 Contatore di programma (program counter) contiene l'indirizzo della
successiva istruzione da eseguire per tale processo.
 Registri di CPU: I registri variano in numero e tipo in base all'architettura, essi
comprendono accumulatori, registri d'indice, stack pointer. Quando si verifica
una interruzione della CPU, tutte queste informazioni insieme al contatore di
programma devono essere salvate su disco (infomazioni presenti nei registri di
CPU durante l'esecuzione), in modo da permettere la corretta esecuzione del
processo in un momento successivo.
 Informazioni sullo scheduling di CPU: Informazioni relative alla priorità del
processo, i puntatori alle code di scheduling e i parametri di scheduling.
 Informazione sulla gestione della memoria: Valori dei registri base e di limite,
tabelle delle pagine/segmenti.
 Informazioni di contabilizzazione delle risorse: tempo d'uso della CPU e il
tempo reale di utilizzo, limiti di tempo, numero dei processi e via dicendo.
 Informazioni sullo stato di I/O: La lista dei dispositivi I/O assegnati ad un
processo, elenco file aperti.
Scheduling dei processi
L'obbiettivo della multiprogrammazione consiste nel disporre della possibilità di
eseguire, non inteso come materialmente eseguito dalla CPU, perché ciò non è
possibile, di più processi contemporaneamente, con lo scopo di massimizzare
l'utilizzo della CPU.
In un sistema con singola CPU di può avere in esecuzione un solo processo alla volta.
Se esistono più processi, quelli che non sono in esecuzione devono aspettare che la
CPU si liberi e la loro esecuzione possa essere ripresa o iniziata
Code di scheduling
Ogni processo è inserito in una coda di processi, composta da tutti i processi del
sistema. I processi presenti nella memoria centrale, che sono pronti e nell'attesa
d'essere eseguiti si trovano in una lista detta coda dei processi (ready queue).
Quando si assegna la CPU a un processo, quest'ultimo rimane in esecuzione per un
certo tempo e prima o poi termina, viene interrotto, oppure si ferma nell'attesa di un
evento particolare, come una richiesta I/O.
Un nuovo processo si colloca inizialmente nella coda dei processi pronti, dove
attende finché non è selezionato per essere eseguito. Una volta eseguito si può
verificare uno dei seguenti eventi:
 Il processo può emettere una richiesta I/O e quindi essere inserito in coda I/O
 Il processo può creare un nuovo processo ed attenderne la terminazione.
 Il processo può essere rimosso forzosamente dalla CPU a causa di una
interruzione ed essere reinserito in coda dei processi pronti.
Il processo termina nel momento in cui non avviene la sua rimozione da tutte le
code, di seguito si rimuove il PCB e si revocano le varie risorse.
Scheduler
Il processo una volta creato si trova nelle varie code di scheduling. Il sistema
operativo, che è incaricato di selezionare i processi dalle suddette code, compie la
selezione per mezzo di un opportuno scheduler. Lo scheduler a lungo termine (job
scheduler), sceglie i lavori da questo insieme e li carica nella memoria affinché siano
eseguiti. Lo scheduler a breve termine (scheduler di CPU) fa la selezione tra i lavori
pronti per essere eseguiti e assegna la CPU ad uno di essi. Lo scheduler a breve
termine seleziona frequentemente un nuovo processo per la CPU. Il processo può
essere in esecuzione solo per pochi millisecondi prima di passare ad attendere una
richiesta di I/O.
Lo scheduler a lungo termine invece si esegue con una frequenza molto inferiore, tra
la creazione di nuovi processi possono trascorrere diversi minuti. Lo scheduler a
lungo termine controlla il grado di multiprogrammazione, cioè il numero di processi
presenti nella memoria.
Un processo con prevalenza I/O (I/O bound) impiega la maggior parte del proprio
tempo nell'esecuzione di operazione di I/O. Un processo con prevalenza di
elaborazione (CPU bound) viceversa, richiede poche operazioni I/O e impiega la
maggior parte del proprio tempo nelle elaborazioni. Per avere prestazioni efficienti le
due code (I/O e CPU) devono essere bilanciate.
In alcuni sistemi si introduce un livello di scheduling intermedio, scheduler a medio
termine, può rimuovere processi dalla memoria (e dalla contesa attiva per la CPU) e
cosi ridurre il grado di multiprogrammazione, successivamente il processo può
essere reintrodotto, questo processo si chiama swapping. Tale processo può servire a
liberare memoria in caso di necessità o a migliorare la combinazione di processi.
Scheduler della CPU
Ogni qual volta la CPU entra nello stato di inattività, il sistema operativo sceglie per
l'esecuzione uno dei processi presenti nella coda dei processi pronti. In particolare lo
scheduler a breve termine o scheduler della CPU che tra i processi nella memoria
pronti, sceglie quello a cui assegnare la CPU. La scelta avviene in base a diversi
algoritmi di scheduling, e generalmente nelle code sono presenti tutti i PCB dei
processi ossia i descrittori.
Scheduling della CPU
Lo scheduling della CPU è alla base dei sistemi multiprogrammati, ed ha come scopo
attraverso il controllo dei vari processi sulla CPU, garantisce al sistema operativo una
maggiore produttività.
In un sistema dotato di una sola unità di elaborazione si può eseguire un solo
processo alla volta, gli altri processi devono attendere che la CPU si libera e possa
essere nuovamente sottoposta a scheduling.
L'idea della multiprogrammazione prevede che un processo è in esecuzione fino a
quando non avviene un’attesa per evento(I/O), in questo lasso di tempo la CPU
sarebbe inattiva, e quindi del tempo sprecato.
Lo scheduling si realizza per quasi tutte le risorse del sistema, ma è chiaro che la CPU
è tra le più importanti.
Ciclicità tra CPU e I/O dei processi
L'esecuzione di un processo avviene alternativamente su due basi, la sequenza di
elaborazioni (CPU burst) e la sequenza di eventi di I/O (I/O burst), poi di nuovo CPU e
di nuovo I/O. Processi I/O bound e processi CPU bound, dei quali già conosciamo la
differenza.
Scheduling con prelazione
Le decisioni riguardanti lo scheduling della CPU si possono eseguire nelle seguenti
circostanze:
1. Un processo dallo stato di esecuzione passa allo stato di attesa (richiesta di
I/O)
2. Un processo dall'esecuzione passa allo stato di pronto (ad esempio in seguito
ad un interrupt).
3. Un processo passa dallo stato di attesa allo stato pronto (completamento di
I/O)
4. Un processo termina la sua esecuzione
Quando lo scheduling interviene solo nelle condizioni 1 e 4 si dice che lo schema di
scheduling è senza il diritto di prelazione (nonpreemptive); altrimenti, lo schema è
con diritto di prelazione. Nel caso dello sheduling senza diritto di prelazione, quando
si assegna la CPU a un processo, questo rimane in possesso della CPU fino al
momento del suo rilascio, dovuto al termine dell'esecuzione o al passaggio nello
stato di attesa.
Dispatcher
Un altro elemento coinvolto nella funzione di scheduling è il dispatcher, il quale è il
modulo che passa effettivamente il controllo della CPU ai processi scelti dallo
scheduler, le funzioni sono:
 Il cambio di contesto;
 Il passaggio al modo d'utente
 Il salto alla giusta posizione del programma utente per riavviarne l'esecuzione.
Il tempo richiesto dal dispatcher per fermare un processo e far eseguire un nuovo
processo viene chiamata latenza di dispatch.
Context-switch (cambio di contesto)
Il passaggio della CPU ad un nuovo processo implica la registrazione dello stato del
processo vecchio e il caricamento dello stato precedentemente registrato del nuovo
processo. Questa procedura è nota col nome di cambio di contesto. Il contesto è
descritto nel PCB di tale processo: include i valori dei registri della CPU, lo stato del
processo e le informazioni di gestione della memoria.
Il tempo necessario al cambio di contesto è puro sovraccarico (overhead), infatti il
sistema non compie nessun lavoro utile durante la commutazione, e varia da
calcolatore a calcolatore in base alla velocità di memoria e registri.
Thread
Per quanto detto fino ad ora un processo è un programma che si esegue seguendo
un unico percorso di esecuzione. Il processo può svolgere un solo compito alla volta.
In molti SO si è esteso il concetto di processo introducendo la possibilità d'avere più
percorsi d'esecuzione, in modo da permettere che un processi possa svolgere più di
un compito alla volta.
Un thread, chiamato anche processo leggero, è l'unità base d'uso della CPU e
comprende un indentificatore di thread (ID) un contatore di programma, un insieme
di registri ed una pila (stack). Un processo tradizionale, è composto da un solo
thread. Un processo multithread è in grado di lavorare a più compiti in modo
concorrente.
I vantaggi della programmazione multithread sono:
 Tempo di risposta: un applicazione interattiva se
esegue un operazione molto lunga, il resto dei
thread può proseguire con l'esecuzione dell'intera
applicazione.
 Condivisione delle risorse: Normalmente i thread
condividono la memoria e le risorse del processo
a cui appartengono.
 Economia: condividendo le risorse non vi è spreco, ed inoltre è più
conveniente gestire i context-switch.
 Uso di più unità di elaborazione: con più CPU è possibile assegnare ad ognuna
un thread, eseguendoli in parallelo e terminando prima l'esecuzione del
processo.
Criteri di scheduling
Esistono diversi algoritmi per lo scheduling della CPU (breve termine) hanno
proprietà differenti e possono favorire particolari classi di processi.
Per classificare questi algortmi per poi fare un accurata scelta di uso, esistono diversi
criteri:
 Utilizzo della CPU: la CPU deve essere più attiva possibile
 Produttività: Una misura del lavoro è data dal numero di processi che si
riescono a completare in una unità di tempo, tale misura viene detta
throughout.
 Tempo di completamento: L'intervallo di tempo che intercorre tra la
sottomissione di un processo e il suo completamento viene detto tempo di
completamento (turnaround time).
 Tempo di attesa: L'algoritmo di scheduling della CPU, influisce solo sul tempo
di attesa nella coda dei processi pronti. Il tempo d'attesa è la somma degli
intervalli d'attesa passati nella coda dei processi pronti.
 Tempo di risposta: tempo che intercorre tra la sottomissione di una richiesta e
la prima risposta prodotta.
Algoritmi di scheduling
Lo scheduling della CPU riguarda la scelta dei processi presenti nella coda dei
processi pronti cui assegnare la CPU.
Scheduling in ordine di arrivo FIFO (FirstComeFirsterve)
E' l'algoritmo più semplice di scheduling della CPU, con tale schema si assegna la
CPU al processo che la richiede per primo, e si basa sul concetto della coda FIFO. Il
tempo di attesa medio è abbastanza alto come si dimostra:
Con questo algoritmo si ha un effetto convoglio, tutti i processi attendono che un
lungo processo liberi la CPU, che causa quindi una riduzione di utilizzo della stessa e
dei dispositivi rispetto a quella che si avrebbe eseguendo per primi i processi più
brevi. L'FCFS è senza prelazione, una volta che la CPU è stata assegnata a un
processo, questo la trattiene fino al momento del rilascio, che può essere come
sappiamo per termine dell'esecuzione o per richiesta I/O.
Scheduling per priorità
Con questo algoritmo si associa ad ogni processo una priorità e si assegna la CPU al
processo con priorità più alta, se vi sono due processi con la stessa priorità si
procede in FCFS.
La priorità interna si definisce usando una o più quantità misurabili come limiti di
tempo, requisiti di memoria, numero di file aperti e la lunghezza media delle
operazioni. Le priorità esterne non dipendono dal calcolatore in se, ma da fattori
esterni decisi dall'uomo, se si affitta ad esempio tempo di CPU.
Lo scheduling per priorità può essere con prelazione o no, nel caso sia con prelazione
se arriva nella coda dei processi pronti un processo con priorità più alta, si opera un
confronto all'arrivo di un nuovo processo, sottrae la CPU al processo che la detiene e
si esegue il processo con priorità più alta, viceversa non succede se non è con diritto
di prelazione ed il processo con priorità più alta viene messo in cima alla coda di
scheduling.
U problema relativo agli algoritmi di scheduling con prelazione è sicuramente la
starvation, l'attesa indefinita. Un processo pronto per l'esecuzione ma che non
dispone della CPU, in questo caso si verifica nel momento in cui un processo ha una
priorità bassa e non riesce ad andare in esecuzione, va quindi in attesa indefinita.
Una possibile soluzione dell'attesa indefinita dei processi a bassa priorità è
l'invecchiamento (aging), si tratta di una tecnica che aumenta gradualmente la
priorità dei processi che attendono da parecchio tempo.
Scheduling circolare (round robin)
Progettato per i sistemi a partizione di tempo, ciascun processo riceve una piccola
quantità di tempo di CPU, chiamato quanto di tempo, e la coda dei processi pronti è
trattata come una coda circolare. Viene pertanto lasciato il quanto di tempo se il
processo termina prima si passa al successivo altrimenti il processo è forzato a
rilasciare.
Per il funzionamento la coda di priorità viene gestita come una coda FIFO, i nuovi
processi si aggiungono alla fine della coda.
Nell'algoritmo RR si assegna la CPU ad un processo per non più di un quanto di
tempo per volta. Se la durata della sequenza di operazioni eccede il quanto di
tempo, il processo viene sottoposto a prelazione e riportato nella coda dei processi
pronti, pertanto RR è un algoritmo con prelazione.
Quando il quanto di tempo è molto largo si riduce in FCFS, mentre quando è molto
piccolo si chiama condivisione della CPU.
Scheduling per brevità (SJF)
Questo algoritmo associa ad ogni processo la lunghezza della successiva sequenza
delle operazioni della CPU. Quando è disponibile, si assegna la CPU al processo che
ha la più breve lunghezza della successiva sequenza di operazioni della CPU. Se due
processi hanno le successive sequenze di operazioni della CPU della stessa
lunghezza, si applica FCFS. Tale algoritmo rappresenta un caso particolare dello
scheduling per priorità.
Come esempio si consideri un insieme di processi, con la durata della sequenza di
operazioni della CPU espressa in millisecondi.
SJF è ottimale perché rende minimo il tempo medio di attesa per un dato insieme di
processi. Sebbene sia ottimale non si può usare per lo scheduling della CPU(breve
termine) poiché non esiste alcun modo per conoscere la lunghezza della successiva
sequenza di CPU. Un possibile metodo è quello di cercare di predire la lunghezza e
scegliere quindi il processo più breve previsto.
SJF può essere con e senza prelazione. La scelta di presenta quando la coda dei
processi pronti arriva un processo con lunghezza inferiore rispetto alla lunghezza di
quello che è attualmente in esecuzione, SJF preemptive sostituisce il processo più
corto con quello attualmente in esecuzione nonpreemptive non esegue questa
operazione. SJF preemptive viene chiamato anche shortest remaining time first SRJF.
Scheduling a code multiple
Una classe di algoritmi di scheduling definisce una distinzione dei processi in base
alle situazione, una tipica distinzione è rappresentata ad esempio come i processi
che si eseguono in foreground, processi interattivi e processi di background. I
processi che si eseguono in foreground possono avere priorità sui processi che si
eseguono in background.
Lo scheduling a code multiple suddivide la coda dei processi pronti in code distinte. I
processi si assegnano in modo permanente ad una delle code, ed ogni coda ha il
proprio algoritmo di scheduling. Ad esempio per i processi in foreground si può usare
RR mentre per la coda di background si può gestire con un algoritmo FCFS.
Tra di loro le code hanno una priorità, pertanto nessuna coda di background può
eseguire processi se sono ancora presenti processi nella coda di foreground. Esiste la
possibilità di assegnare quanti di tempo alle code.
Esiste anche lo scheduling a code multiple con retroazione, che a differenza di quello
normale permette ai processi di spostarsi fra le code. Se per esempio un processo
molto lungo occupa molto tempo di elaborazione viene spostato nelle code a
priorità più bassa, viceversa processi con più I/O vengono spostati nelle code con
priorità più alta.
Sincronizzazione dei processi
Un processo cooperante è un processo che può influenzare un altro processo in
esecuzione nel sistema o anche subirne l'influenza. I processi cooperanti possono
condividere direttamente uno spazio logico di indirizzi oppure anche solo dati
attraverso i file.
Deduzione logica dice che se più processi accedono e modificano gli stessi dati con al
conseguenza logica di errori frequenti, poiché più processi possono modificare il
valore di variabili e condurre a stati errati.
Per evitare situazioni di questo tipo, in cui più processi accedono e modificano gli
stessi dati in modo concorrente e i risultati dipendono dall'ordine degli accessi race
condition, occorre assicurare che solo un processo per volta possa modificare alcune
variabili.
Problema della sezione critica
Considerando un insieme di processi cooperanti, aventi ognuno un segmento di
codice chiamato sezione critica, nel quale il processo può cambiare variabili comuni,
aggiornare tabelle o scrivere in un file etc. Quando un processo è in esecuzione nella
propria sezione critica, non si deve consentire a nessun altro processo di essere in
esecuzione nella propria sezione critica. Quindi l'esecuzione della sezione critica dei
processi è mutuamente esclusiva nel tempo. Una soluzione al problema della
sezione critica deve soddisfare i tre seguenti requisiti:
1. Mutua esclusione: se un processo è in esecuzione nella sua sezione critica,
nessun altro processo può eseguire la propria sezione critica.
2. Progresso: Solo i processi che si trovano fuori dalle sezioni non critica possono
partecipare alla decisione riguardante la scelta del processo che può entrare in
sezione critica per primo.
3. Attesa limitata: Se un processo ha richiesto di entrare in SC esiste un limite di
volte che si consente agli altri processi di entrare nelle proprie SC prima di
accordare la richiesta al primo processo.
Semafori
Una delle soluzione per risolvere il problema della sezione critica è l'uso dei
semafori. Un semaforo è una variabile intera in cui si può accedere, escludendo
l'inizializzazione, solo tramite due operazioni atomiche predefinite wait e signal. Le
modifiche ai valori del semaforo devono avvenire in maniera atomica, mentre un
processo cambia valore al semaforo nessun altro processo può modificare quello
stesso valore.
Mentre un processo si trova nella propria sezione critica, qualsiasi altro processo che
tenti di entrare in SC si trova sempre nel ciclo della sezione di ingresso, questa viene
definita come attesa attiva. Questo rappresenta un problema nei sistemi a
multiprogrammazione in quanto l'attesa attiva occupa cicli di CPU che altrimenti
potrebbero essere utilizzati in altra maniera. Questo tipo di semaforo viene detto
spinlock ed ha come punto di forza il fatto che non si deve compiere alcun cambio di
contesto. Per ovviare a questo problema si può indicare ad ogni processo di bloccarsi
nel momento in cui debba andare in attesa attiva, al segnale non positivo del
semaforo.
Un possibile problema che si può verificare con un semaforo con coda di attesa è che
può condurre a situazioni nelle quali i processi attendano indefinitamente un evento,
che può essere causato solo da uno dei processi dell'insieme. Tale situazione si dice
che i processi siano in deadlock.
Problema dei 5 filosofi a cena
Si considerino 5 filosofi che passano la vita pensando e mangiando. I filosofi dividono
un tavolo rotondo con 5 sedie, una per ognuno, al centro del tavolo si trova la
zuppiera con il riso, e la tavola è apparecchiata con cinque bacchette.
Quando un filosofo pensa non interagisce con i colleghi, quando gli viene fame, tenta
di prendere le bacchette più vicine: quelle che si trovano tra lui e i commensali a dx e
a sx. Un filosofo può prendere una bacchetta alla volta e non può prendere una
bacchetta che è nelle mani di un suo vicino. Quando un filosofo decide di mangiare
afferra due bacchette se sono disponibili, mangia senza lasciarle, terminato le riposa
e riprende a pensare.
Una semplice soluzione consiste nel rappresentare ogni bacchetta con un semaforo,
da segnale wait al semaforo quando la afferra e signal quando la posa. Questa
soluzione garanti che due vicini non mangino, ma non evita possibili situazioni di
stallo. Mettiamo caso che tutti i filosofi abbiano fame contemporaneamente ed
afferrino la bacchetta di sx, tutti sarebbero inevitabilmente in attesa della bacchetta
dx, creando una situazione di stallo.
Possibili soluzioni a questo problema sono: solo 4 filosofi possono mangiare
contemporaneamente, un filosofo può prendere le bacchette solo se entrambe
disponibili, oppure filosofo dispsri prendere prima la bacchetta sx, e i filosofi pari
prima la bacchetta sx.
Situazioni di stallo
In uno stallo i processi non terminano mai l'esecuzione e si bloccano le risorse di
sistemi impedendo l'esecuzione di altri processi. Affinché si verifichi uno stallo solo
se si verificano queste 4 condizioni:
1. Mutua esclusione: Almeno una risorsa non deve essere condivisibile, vale a
dire che non può essere usata da un solo processo alla volta.
2. Possesso e attesa: Un processo in possesso di almeno una risorsa attende di
acquisire risorse già in possesso di altri processi.
3. Impossibilità di prelazione: Non esiste un diritto di prelazione sulle risorse,
cioè una risorsa non può essere lasciata da un processo, fino a che
quest'ultimo non lo faccia volontariamente.
4. Attesa circolare: Dato un insieme di processi, tale che ogni processo attenda
una risorsa posseduta da un altro, in maniera circolare.
Le quattro condizioni non sono del tutto indipendenti, cioè nell'attesa circolare
troviamo possesso è attesa.