7.5 Lo scheduler

Poiché GNU/Linux è un sistema multitasking, deve gestire la presenza contemporanea di più processi che girano “contemporaneamente” sulla macchina. Questo ovviamente non è fisicamente possibile poiché generalmente le macchine hanno una sola CPU ed una CPU può eseguire soltanto un’operazione per volta36. Quindi viene adottata la tecnica di assegnazione di intervalli di tempo (time slice) da dedicare ad ogni singolo processo. In questo modo un processo viene eseguito fintantoché il time slice ad esso riservato non è terminato, dopodiché viene sospeso. Il sistema poi determina quale sia il prossimo processo da attivare ed il time slice da assegnargli. E così via.

Lo scheduler è la parte del kernel che si preoccupa di gestire l’attivazione e la sospensione dei processi secondo una determinata logica detta anche politica di scheduling. La scelta del meccanismo in grado di distribuire l’opportuno time slice ai vari processi non è cosa banale ed è importante notare il fatto che non esiste un sistema ottimale per la temporizzazione dei processi, ma dipende in maniera essenziale dall’utilizzo che si intende fare del sistema.

Una delle caratteristiche principali di un sistema mutitasking è quella di gestire un prehemptive multitasking, ovvero il sistema operativo assegna il tempo di CPU ai processi della durata massima del time slice relativo ed il processo può rilasciare la CPU anche prima che sia scaduto il suo time slice, ma nel caso in cui il time slice scada, il sistema operativo stesso (lo scheduler) sospende il processo e riprende il controllo del sistema, “calcolando” a quale processo cedere la CPU per il successivo time slice. Nei sistemi cooperative multitasking invece il rilascio della CPU è demandato ai singoli processi: se un processo si appropria della CPU senza mai rilasciarla agli altri, il sistema può diventare inutilizzabile, poiché lo stesso utente non riesce più ad interagire con il sistema stesso.

In un sistema GNU/Linux un processo può trovarsi in uno dei seguenti stati (tra parentesi è riportato la lettera corrispondente visualizzata dal comando ps):

È importante tenere presente il fatto che il tempo di CPU assegnato ad un processo è soltanto quello destinato allo sfruttamento di una risorsa del sistema, ma non è detto che tale risorsa sia quella più importante per il processo (molti processi dipendono in maniera più pesante dall’I/O). Pertanto dare ad un processo una priorità elevata rispetto agli altri può, in certi casi, non portare ad un significativo incremento delle prestazioni dello stesso.

Il meccanismo di scheduling tradizionale dei sistemi Unix-like si basa sul concetto di priorità dinamica: un processo che ottiene il diritto di utilizzare la CPU per la durata del time slice, vede abbassarsi di priorità in modo tale che più o meno tutti i processi (anche quelli con priorità molto bassa) possano utilizzare la CPU per il prorio time slice. La priorità (dinamica) di un processo viene indicata con un numero intero decrescente: ad una priorità più elevata corrisponde un valore più basso.

Lo standard POSIX ha introdotto anche il concetto di priorità assoluta (o statica), per tener conto dei sistemi real-time, in cui è indispensabile che determinati processi (critici) non debbano attendere l’esecuzione di altri (non critici)37. In tal senso, tra due processi che si contendono l’esecuzione (nello stato runnable) “vince” quello che ha la stessa priorità assoluta maggiore. La priorità assoluta viene indicata con un numero intero crescente: ad una priorità assoluta più elevata corrisponde un valore più alto.

In genere nei sistemi GNU/Linux a tutti i processi viene assegnata la stessa priorità assoluta pari a 0 e quindi lo scheduling si basa soltanto sul meccanismo della priorità dinamica. In particolare, normalmente anche il valore di priorità dinamica è impostato a 0 per tutti i processi.

Poiché l’accesso alle risorse non è istantaneo, è possibile che un processo non esaurisca l’accesso alla risorsa nel time slice ad esso assegnato. Quindi, in qualche modo il kernel si annota il fatto che un determinato processo sta accedendo ad una specifica risorsa, segnandola come occupata, in modo tale che un altro processo non vada a modificare i dati del primo (si pensi ad esempio ad una stampante e a cosa accadrebbe se un due processi stampassero sulla stessa stampante senza nessun meccanismo di gestione di tale risorsa: si mischierebbero inevitabilmente gli output dei due processi). Dunque un ulteriore processo che desidera accedere alla stessa risorsa, anche se il suo time slice non è scaduto, viene sospeso.

L’algoritmo di scheduling, che decide a quale dei processi assegnare il prossimo time slice di utililzzo della CPU, in genere si basa sui seguenti parametri:

È possibile modificare la priorità (dinamica) di un processo con il comando nice (man page nice(1)).

____________________________________________________________________

Comando: nice
Path: /bin/nice

SINTASSI  
$ nice [option] [command [args]]  
DESCRIZIONE

____________________________________________________________________

Il nome del comando deriva dal fatto che in genere questo viene utilizzato per ridurre la priorità di un processo, come “cortesia” nei confronti degli altri.

Esiste anche la possibilità di modificare il valore della priorità (dinamica) di un processo mentre questo è in esecuzione. Questo può essere fatto con il comando renice (man page renice(8)).

__________________________________________________________________________________________________________

Comando: renice
Path: /usr/bin/renice

SINTASSI  
$ renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]  
DESCRIZIONE

______________________________________________________________

[da completare ...]


  7.5.1 La gestione dei processi