Non sei ancora registrato? Cosa aspetti, corri a farlo QUI !!
Non sei ancora registrato? Cosa aspetti, corri a farlo QUI !!







![]() | Oggi | 687 |
![]() | Ieri | 2080 |
![]() | Questa settimana | 10394 |
![]() | Scorsa settimana | 13053 |
![]() | Questo mese | 6427 |
![]() | Scorso mese | 61539 |
![]() | Globali | 2930612 |
Lunedì 04 Maggio 2009 08:18
Non il classico articolo sull'ultimo sistema operativo Windows, Mac o Linux bensì una sorta di guida alla scoperta del generico sistema operativo visto da un punto di vista più propriamente tecnico, senza però calarci troppo in incomprensibili e superflui tecnicismi.
Il sistema operativo è il gestore delle risorse (CPU, RAM, dispositivi I/O, memoria di massa) dell’elaboratore. Nella gestione di una risorsa hardware, il sistema operativo deve seguire quattro passi:
Una classificazione intuitiva dei sistemi operativi è la seguente:
Secondo l’uso, i sistemi operativi si classificano in:
Il sistema operativo è un software estremamente complesso, per cui è necessaria una certa organizzazione per poterlo realizzare correttamente. Il sistema operativo si divide in moduli, ciascuno dei quali ha uno specifico compito e sono interconnessi tra loro. La struttura gerarchica di un sistema operativo, che si compone di moduli, è la seguente:
I moduli dovrebbero essere quanto più possibile indipendenti tra loro: sostituendo anche solo un modulo, il sistema operativo deve essere in grado di continuare a funzionare correttamente.
Il job è la singola richiesta di utilizzo di una risorsa, presente all’interno del programma in via di esecuzione.
Il processo è l’esecuzione di un job: è il job associato alla risorsa richiesta.
Il processore è quel dispositivo che consente di eseguire i processi.

Il traffic controller è un modulo del sistema operativo che analizza lo stato delle periferiche e, quando queste sono attive, risveglia il job riportandolo poi alla fase di pronto. Il process scheduler decide quali fra i processi in coda, in stato di pronto, può ottenere la CPU. Il job scheduler fa transitare dallo stato di acquisizione a quello di pronto.
Il tempo totale di esecuzione di un programma è dato dalla somma dei tempi dei job più i tempi di attesa w (wait), ovvero quando il job attende i dati che devono arrivare dalle periferiche di I/O. Sfruttando i tempi di attesa, due programmi possono essere eseguiti in parallelo. Tutto ciò è appunto possibile se ci sono tempi di attesa, altrimenti se non ce ne sono non vale la pena nel caso di singola CPU; se però la CPU è coadiuvato da altri chip come il DMAC si creano tempi di attesa per la CPU che resta inutilizzata e quindi è possibile sfruttarla.
Tutti i moderni linguaggi di programmazione dispongono di costrutti per programmare in parallelo. Il costrutto fork/join è usato in C: quando si vuol ad esempio farm andare una procedura in parallelo con l’esecuzione del programma principale, si invoca il comando fork seguito dal nome della procedura. Il join, a cui andrà sempre affiancato il nome della procedura, serve al programma principale per interrogare il processo (procedura) che si sta eseguendo in parallelo e, nel caso la procedura non è ancora terminata, il programma ne attenderà il termine. In Java si usano i thread per eseguire azioni in parallelo, mentre per altri linguaggi esistono altri costrutti per la programmazione in parallelo tra cui il cobegin/coend.
Nella programmazione concorrente, due o più processi concorrenti competono per l’attribuzione di una stessa risorsa, cercando di usarla nello stesso istante. Dunque il sistema operativo deve poter regolamentare l’utilizzo e l’accesso alle risorse. Due processi che concorrono possono trovarsi in tre situazioni distinte:
I semafori sono l’idea più facile per consentire l’accesso ordinato ad una risorsa. Si tenga presente un semaforo con una luce rossa (risorsa impegnata e quindi non accessibile) ed una luce verde (risorsa libera, a disposizione di un processo). Il principio del semaforo utilizza due funzioni elementari del sistema operativo (dette primitive), che usano una variabile s (0: risorsa occupata ; 1: risorsa libera); le due funzioni sono P(s) e V(s). La funzione P(s) viene richiamata dal processo che vuole occupare la risorsa e se dal controllo risulta che s=1 allora la risorsa è libera e accessibile, altrimenti in caso contrario (0) bisognerà aspettare finché il flag scatti a 1. Quindi a questo punto per far sì che la risorsa venga attribuita al processo viene settato s=0 (occupato). Infine richiamando la funzione V(s) s verrà settato ad 1, per liberare la risorsa, il che significa che la risorsa tornerà ad essere nuovamente disponibile per altri processi:


In questo modo, alla fine ognuno deve liberare il semaforo dell’altro.

Il semaforo generalizzato diviene semaforo binario se il valore di partenza, S, è ad 1.
Un sistema è in stallo (o in dead lock) quando i processi non riescono ad andare a termine. Lo stallo è una situazione imprevedibile ma verificabile a causa del numero di processi elevato in esecuzione nel sistema. Un esempio di stallo è dato dal seguente grafico, detto grafo di allocazione delle risorse:

Nei cerchi vengono indicati i processi, mentre nei quadrati le risorse. Quando una freccia va da una risorsa a un processo vuol dire che quella risorsa è assegnata a quel processo; quando invece la freccia va dal processo alla risorsa vuol dire che il processo richiede l’uso della risorsa per andare avanti. Nella situazione in esempio, P1 ha assegnato R1 e per andare avanti ha bisogno di R2, mentre P2 ha assegnato R2 e per andare avanti ha bisogno di R1. Questa, più che stallo, è detta attesa circolare: solo se tutti i processi del sistema sono in attesa circolare il sistema è in stallo.
Per risolvere queste situazioni di contesa delle risorse si usano i semafori, tuttavia va eliminato il busy waiting, ovvero quell’attesa occupata che si verifica quando il processo esegue il P(s) per interrogare circa la disponibilità di una risorsa. Difatti così facendo il processo impegna la CPU senza fare nulla. Non è uno stallo ma è qualcosa che bisognerà evitare nella realizzazione dei semafori. Difatti queste primitive di base sono superate dai monitor, funzioni efficienti per garantire la sincronizzazione tra processi.
Può avvenire uno stallo se:
Uno stallo si può prevenire, o riconoscerlo ed eliminarlo:
MECCANISMI DI PREVENZIONE:
MECCANISMI DI RICONOSCIMENTO E “CURA”:
Lo starvation è una situazione di blocco individuale, in cui c’è un certo numero di processi che non va avanti mentre comunque gli altri continuano il loro lavoro: ad esempio se il sistema operativo assegna le risorse solo ai processi a priorità alta, ignorando quelli a priorità bassa.
Mentre Windows 95 e Windows 98 sono diversi da Windows 2000 in quanto molto legati a MS-DOS, Windows NT era già un sistema operativo di classe server, distaccato dal DOS, e Windows 2000 riprende NT irrobustendolo e rendendolo più stabile e con una gui più avanzata, facendolo diventare un sistema operativo anche per il client. Windows 2000 è organizzato su tre livelli: modo utente e modo kernel (che si occupa della gestione di interrupt e servizi richiesti dagli altri moduli del SO) scritti in linguaggio C object-oriented, e il modo HAL (hardware abstraction layer) scritto in assembly. Le applicazioni usano le API (application program interface), che sono delle funzioni standard usate per accedere a determinati sottomoduli del sistema operativo.
UNIX è un sistema operativo nato alla fine degli anni Sessanta che poteva funzionare solo su macchine con hardware dell’epoca potenti (mainframes). Era multitasking e progettato per un uso interattivo. Dalla prima versione di Unix ne sono nate altre, dopodiché Linus Torvald, come tesi universitaria, creò un piccolo kernel con un minimo di funzioni di base per un sistema operativo e pubblicò il suo risultato su internet; grazie dunque alla “pubblicità” di internet, ma anche all’hardware del tempo più potente, in poco tempo ha avuto supporto da altri utenti e in pochi anni è nata una comunità di sviluppo del sistema operativo che sarà chiamato Linux, le cui caratteristiche principali sono: multitasking; una o più shell (interprete dei comandi, interfaccia a riga di comando molto usata in ambiente server in sostituzione di una GUI); un file system con struttura ad albero; supporto alla rete con meccanismi di protezione elevati. Nelle prime versioni, il kernel di Linux era monolitico e dunque doveva essere caricato interamente nella RAM, mentre in seguito venne diviso in moduli in modo da caricare in memoria solo i moduli necessari. In linux l’unità fondamentale è il processo, inteso come una serie di azioni in esecuzione. Ogni programma genera più processi e in alcuni momenti i processi sono in attesa di ricevere una risorsa (sono in wait, “addormentati”). Linux utilizza il fork all’interno di un programma in esecuzione per generare un nuovo processo figlio, identico al processo padre, ma individuato da un codice numerico (PID) differente, che potrà svolgere in parallelo altre operazioni. Linux è scritto interamente in C classico, non object oriented.

