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.