istituto tecnico e liceo scientifico tecnologico “angioy”

ISTITUTO TECNICO E LICEO SCIENTIFICO TECNOLOGICO “ANGIOY”
informaticangioy.altervista.org
I SISTEMI OPERATIVI
Prof. G. Ciaschetti
1. Introduzione
Un Sistema Operativo (abbreviato in SO o OS a seconda che si usi l’italiano o l’inglese Operating
System) è un insieme di programmi che gestiscono e rendono disponibile ad altri programmi le
risorse del computer. Esso quindi costituisce il software di base del computer, al quale si
appoggiano gli altri software, detti applicazioni, per accedere alle risorse hardware.
La situazione è descritta nella seguente figura:
Le applicazioni chiedono al Sistema Operativo l’uso delle risorse hardware, ed esso consente tale
uso nei modi e nei tempi che ritiene più opportuni. Quando, ad esempio, scriviamo un’istruzione in
un programma in linguaggio C (cioè un’applicazione) che richieda di accedere alla memoria RAM,
o che debba leggere dati da un file, o ancora che richieda l’uso di dispositivi di input/output, o in
tante altre situazioni, sarà il Sistema Operativo a occuparsi di soddisfare tale richiesta. La richiesta
al Sistema Operativo non avviene in modo esplicito da parte del programmatore, ma avviene per
mezzo del compilatore (ricordate? Un compilatore è quel software che permette di tradurre i nostri
programmi scritti in C++ in linguaggio binario, per far sì che siano eseguibili), il quale sa come
specificare l’istruzione per quel particolare Sistema Operativo che stiamo usando. Per questo
motivo, ogni diverso Sistema Operativo ha il suo particolare compilatore (ad esempio, esiste un
compilatore Dev-C++ per Windows, uno per il MAC-OS, uno per Linux, ecc.).
Per fare un altro esempio, supponiamo che stiamo usando un programma di videoscrittura (come
Word) e invochiamo la stampa del documento: l’applicazione (Word) richiederà la stampa al
Sistema Operativo, il quale apre la cartella delle stampanti permettendo di selezionarne una, oltre
alle varie opzioni di stampa, quindi invia il file da stampare alla stampante (l’hardware).
Un altro modo possibile di vedere il Sistema Operativo è dal punto di vista degli utenti: esso
rappresenta l’interfaccia tra l’utente e il computer: una volta acceso il computer, il Sistema
Operativo mette a disposizione un ambiente nel quale è possibile eseguire tutta una serie di
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
operazioni (esecuzione di programmi, visualizzazione dei file e delle cartelle, ecc.), cioè quello che
noi chiamiamo “usare il computer”.
Un Sistema Operativo è organizzato in moduli stratificati tra loro. Ogni modulo comunica con i
moduli immediatamente adiacenti mediante delle funzioni dette primitive. Il principio è un po’
quello dell’incapsulamento nella programmazione orientata agli oggetti: un modulo conosce cosa sa
fare un modulo adiacente (conosce, cioè, la definizione delle primitive e come vanno usate), ma non
come lo fa (cioè, come esse sono implementate). Le primitive del modulo più esterno, quelle usate
dalle applicazioni, sono chiamate API (Application Programming Interface). Lo schema della figura
precedente, allora, possiamo vederlo più in dettaglio come segue:
Prima di iniziare a vedere in dettaglio come funziona un sistema operativo, torniamo un secondo
alla prima definizione che abbiamo dato, il SO come gestore delle risorse del computer: ma quali
sono le risorse che il SO gestisce? Possiamo racchiuderle in quattro grandi categorie:

memoria RAM

tempo di utilizzo della CPU

dispositivi periferici (stampanti, mouse, tastiera, video, CD-ROM, ecc.)

files
Vedremo come i diversi moduli del SO si occupano di gestire ognuna di queste quattro categorie di
risorse.
2. Storia
I sistemi batch
I primi computer riuscivano a eseguire una sola sequenza di istruzioni (da qui batch, letteralmente
lotto di istruzioni) per volta. Di conseguenza, i primi sistemi operativi servivano solo per permettere
l’immissione nel computer (tramite schede perforate) dei dati e del programma da svolgere.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Nessuna interazione tra l’uomo e la macchina era permessa durante l’elaborazione. Inoltre, era
possibile avere dei report sul risultato dell’elaborazione e sullo stato della macchina.
I sistemi multiprogrammati
A partire dagli anni 60, si è cominciato a usare il computer in modo più massiccio, con conseguente
aumento delle richieste di calcolo. Nasceva l’esigenza di eseguire, con lo stesso computer, più
programmi contemporaneamente. E’ in questo momento che è nato UNIX, il primo vero sistema
operativo, capace di gestire la multiprogrammazione e tutte le problematiche ad essa connessa,
effettuando lo scheduling di lungo termine (che prendono il nome di lavori, da cui il termine job
scheduling), ossia la scelta di quali lavori caricare in memoria dal disco, e lo scheduling della CPU
(cpu scheduling), o di breve termine ossia la scelta di come ripartire la CPU tra i vari lavori presenti
in memoria. La logica di questi sistemi è sostanzialmente quella dei sistemi batch, con la sola
differenza che stavolta possono essere mantenuti in memoria ed eseguiti più programmi per volta,
ed è il SO che organizza la memoria RAM e il lavoro della CPU tra i diversi programmi.
I sistemi multitasking
Agli inizi degli anni 70, l’uso del computer era ormai diventato molto diffuso, e iniziavano a
nascere i primi computer dipartimentali collegati a più terminali, ognuno dei quali usato da un
diverso operatore. Si tratta dei sistemi di tipo client-server (il terminale è il client, il computer
centrale o mainframe è il server), in cui occorre gestire oltre che più programmi, anche più utenti
contemporaneamente. Si tratta di una successiva evoluzione del sistema UNIX, in cui ogni lavoro di
ogni utente è chiamato compito (o task in inglese, da cui il termine multitasking). Questo tipo di SO
doveva provvedere a gestire un elevato e frequente numero di accessi alla memoria, introducendo
anche dei meccanismi di protezione dei dati tra i diversi utenti. Inoltre, ogni utente doveva avere
l’impressione di avere a disposizione “per sé” le risorse di elaborazione, senza dover aspettare il
completamento degli altri compiti degli altri utenti. Nasce così il concetto di time-sharing, cioè
della divisione del tempo di CPU in slot temporali di durata piccolissima: viene assegnato a ogni
slot un diverso compito dei vari utenti, i quali così non fanno in tempo a rendersi conto di aspettare
tra uno slot e l’altro.
I sistemi user-friendly
Nel 1977 nasce il primo personal computer: l’Apple II. Esso segna l’inizio di una nuova era per
l’informatica, poiché si passa dall’uso lavorativo all’uso domestico del computer, abbracciando una
moltitudine di nuovi utilizzatori. Nasce così l’esigenza di rendere “agevole” la macchina
calcolatrice anche ai non esperti: i sistemi operativi che nascono in questo periodo si concentrano
soprattutto nello sviluppo dell’interfaccia uomo-macchina, utilizzando sistemi di comando per il SO
più agevoli della semplice tastiera. E’ nel 1984 che, con l’Apple McIntosh, Steve Jobs e Steve
Wozniak inventano il primo sistema operativo con interfaccia WIMP (Windows, Icons, Mouse and
Pointer). Successivamente, tale interfaccia sarà ripresa anche da altri sistemi operativi, come lo
stesso UNIX, Windows, e la versione gratuita e open source di Unix, Linux).
I sistemi distribuiti e multiprocessore
Con la nascita negli anni 80 delle reti di computer di tipo peer-to-peer, in cui più computer di uguali
caratteristiche sono collegati tra loro per condividere alcune risorse, quali stampanti e file, nasce la
possibilità di utilizzare più processori contemporaneamente per eseguire uno stesso insieme di
elaborazioni: uno stesso programma viene eseguito su più computer “paralleli” per sfruttare
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
maggiori risorse di calcolo, e quindi terminare prima (si pensi a programmi che richiedono giorni o
mesi di elaborazione, come quelli per la cifratura di codici o per la soluzione di problemi
complessi). I sistemi operativi si specializzano allora nella gestione di più processori
contemporaneamente, inizialmente dislocati su diversi computer in rete, attualmente comunemente
montati su uno stesso computer (si pensi al processore Intel Core Duo, ad esempio, due processori
in uno).
I sistemi mobili
A partire dagli anni 90, con l’avvento dei telefoni cellulari, sempre più ricchi di utility e di
applicazioni per lo svago, e dei computer palmari (PDA, Personal Digital Assistant), nasce
l’esigenza per i SO di avere buone prestazioni a costi contenuti, e soprattutto di risparmiare energia.
Nascono così sistemi operativi più leggeri che ottimizzano l’uso delle risorse da un punto di vista
energetico, come Windows Mobile, Symbian o Palm OS.
3. Il nucleo
Il modulo più importante di un SO è quello che si occupa della gestione dei processi: il nucleo o
kernel. Ricordiamo che un processo è un programma in esecuzione (un programma è un’entità
statica, mentre un processo è un’entità dinamica). Per ogni processo in esecuzione, il nucleo del SO
mantiene un insieme di informazioni relative al processo in un PCB (Process Control Block), che
memorizza:
 il numero del processo (ogni processo viene contraddistinto da un numero progressivo dal
SO)
 lo stato del processo
 il program counter (a che punto si trova la sua esecuzione, cioè qual è la prossima istruzione
da eseguire)
 lo stato dei registri della CPU
 le informazioni relative allo scheduling del processo (priorità, ecc.)
 le informazioni relative alla memoria dedicata al processo (indirizzi, ecc.)
 la lista dei file aperti usati dal processo (in scrittura e in lettura).
I processi possono essere single thread o multi thread, cioè avere un solo canale di esecuzione o più
canali di esecuzione (un esempio di processo single thread è il Paint di Windows: è possibile fare un
solo disegno per volta; un esempio di processo multi thread è Word, che permette di avere più
documenti aperti nello stesso programma). Anche nel caso di processi multi thread, comunque, si ha
un solo PCB e non uno per ogni thread.
I processi tra loro possono essere concorrenti (che si contendono le risorse), cooperanti (che
hanno un obiettivo comune, dunque non importa se le risorse vengono assegnate a uno oppure a un
altro, va bene comunque), oppure indipendenti (assenza di conflitto di risorse). In ognuno di questi
casi, il SO gestisce la ripartizione delle risorse tra i diversi processi. In particolare, nel caso di
processi cooperanti, il SO mette a disposizione un meccanismo semaforico per la loro
sincronizzazione e le primitive send e receive per lo scambio di messaggi. Inoltre, mediante la
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
primitiva RPC (Remote Procedure Call) un processo può richiedere al SO l’esecuzione di un altro
processo.
Ciclo di vita di un processo
Abbiamo visto che essendo le risorse di un computer “scarse”, cioè limitate, esse devono essere
opportunamente ripartite tra i diversi processi in esecuzione. Di conseguenza, un processo può
trovarsi in diversi stati, a seconda che esso sia stato o meno caricato in memoria RAM, che abbia o
no disponibilità della CPU per l’elaborazione, o che sia in attesa di qualche operazione di
input/output. Nella seguente figura sono mostrati i possibili stati in cui un processo può trovarsi, e
le transizioni da uno stato all’altro.
Nel momento in cui si fa doppio click su un file eseguibile (un programma), il processo è creato.
Solo quando verrà caricato nella memoria dal Long Term Scheduler, (un software del nucleo che
realizza lo scheduling di lungo termine), esso passa dallo stato creato allo stato pronto. Deve, però,
competere con gli altri processi per la risorsa CPU, per poter essere eseguito. Questo conflitto è
risolto dallo Short Term Scheduler (un altro software del nucleo), il quale ripartisce il tempo di CPU
tra i diversi processi secondo determinate strategie di scheduling. Se selezionato, il processo passa
dallo stato pronto allo stato in esecuzione, viene caricato il suo PCB, e quando invece
deselezionato ritorna allo stato pronto. Il cambiamento del PCB del processo attualmente in
esecuzione viene chiamato context-switch.
Mentre il processo è in esecuzione, può accadere che esso richieda un’operazione di input/output,
che interessi cioè un dispositivo periferico (come abbiamo già accennato, è il SO a occuparsi anche
di questo, ma con un altro modulo, non il nucleo), la quale richiede molto tempo rispetto alla
velocità del processore, circa 1 milione di volte più lenta. Mentre aspetta che si compia
l’operazione, esso viene posto nello stato in attesa per poi essere nuovamente posto nello stato
pronto quando il dispositivo periferico comunica al SO di aver terminato l’operazione mandando
un segnale di interrupt (interruzione: “hey, io ho finito, fermati un attimo, prestami attenzione!”).
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Il processo è posto nello stato in attesa anche in caso di chiamate al sistema (come l’istruzione
system(“pause”), per intenderci) che generano una trap, ossia l’esecuzione di speciali routine di
priorità assoluta. Non appena terminata trap, il processo torna ad essere pronto per essere di nuovo
schedulato.
Gestione degli eventi (interrupt/trap)
Allo scopo sapere da quale dispositivo periferico (mouse, tastiera, disco, video, ecc.) arriva la
richiesta di interruzione, o IRQ (Interrupt ReQuest), o se si tratta di una chiamata di sistema, il
nucleo del SO mantiene un vettore degli interrupt, un vettore di bit (1 = interruzione, 0 = nessuna
interruzione) in cui ogni posizione corrisponde a un diverso dispositivo periferico. Alcune posizioni
sono quindi riservate al sistema. Il vettore viene continuamente monitorato dal SO, che fa partire
immediatamente la routine di gestione dell’interruzione o la trap, avviando un context-switch.
CPU scheduling
Ogni diversa scelta dello scheduler dà luogo a diverse prestazioni del sistema. E’ opportuno allora
che l’algoritmo faccia le migliori scelte possibili. Ogni possibile soluzione può essere rappresentata
su un diagramma di Gantt, in cui si riporta una linea per ogni processore, che rappresenta l’asse dei
tempi, e un rettangolo di altezza fissa e lunghezza pari alla durata del processo, ossia il tempo di
CPU che esso richiede per la sua esecuzione, come nella figura che segue:
Diversi indicatori di prestazione dell’algoritmo di scheduling di breve termine possono essere
usati:
- percentuale di utilizzo della CPU: si schedulano i processi per massimizzare il tempo in cui la CPU
o le CPU, se più di una, lavorano. Equivale a minimizzare il numero di context-switch.
- troughput: si massimizza il numero di processi terminati nell’unità di tempo.
- Cmax: indicando con Ci l’istante di completamento dell’i-esimo processo, e con Cmax il massimo
di questi tempi, si minimizza quest’ultimo, il che equivale a minimizzare l’istante in cui si
terminano tutti i processi. E’ anche un indicatore di bilanciamento dei lavori nei sistemi
multiprocessore: infatti, minore è il tempo per completare tutti i lavori, più equa è la
ripartizione di essi.
- media dei tempi di completamento iCi/N: si miminizza il tempo medio di completamento dei diversi
processi: questo indicatore è molto usato nei diversi benchmark dei processori.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Per raggiungere questi obiettivi, l’algoritmo di scheduling può funzionare in modo
 FCFS (First Come First Served): i processi sono gestiti in coda, quindi in modo FIFO.
 SPT (Shortest Processing Time first): viene schedulato prima il processo che dura meno.
Questo algoritmo minimizza il tempo medio di completamento dei processi.
 Priorità: può essere statica o dinamica. Nel primo caso, riguarda l’importanza del processo,
nel secondo può crescere all’aumentare del tempo d’attesa del processo.
 Round Robin: si assegna a rotazione la CPU ai diversi processi, suddividendo il tempo in
slot temporali.
4. La gestione della memoria
Un altro importante modulo del SO si occupa di gestire la memoria del computer. Soprattutto,
parliamo di gestione della memoria di lavoro, la RAM, dove devono risiedere i programmi per
essere eseguiti. Ricordiamo che è il Long Term Scheduler che assegna la memoria ai diversi
processi. Questo può non essere un problema, (al giorno d’oggi un normale PC ha una memoria
RAM da 2 a 4 GigaByte, spesso sufficienti per i pochi programmi per volta che eseguiamo
quotidianamente), ma diventa di fondamentale importanza quando il numero di processi simultanei
tende a crescere.
L’operazione di caricamento/scaricamento dalla RAM di un processo, da parte dello scheduler di
lungo termine, è chiamata swapping (scambio: un processo torna sul disco mentre uno viene
caricato in memoria).
Quando scriviamo un programma, in linguaggio C o in un altro linguaggio di programmazione,
molte istruzioni fanno riferimento alla memoria: ad esempio, l’istruzione N = N + 1; richiede di
prelevare in memoria, all’indirizzo della variabile N, il valore di tale variabile, quindi sommare 1, e
successivamente di memorizzare nello stesso indirizzo il risultato. Il fatto è che al momento della
scrittura del programma non è noto l’indirizzo di N. E non sarà noto finché il programma non
diventerà un processo, cioè creato (quando si fa doppio click) e posto in memoria (stato di pronto).
Quello che accade in realtà è che al momento della compilazione di un programma, viene generato
dal compilatore un codice rilocabile, fatto di indirizzi logici (a partire dall’inizio del programma,
ecc., ), che diventeranno indirizzi fisici veri e propri solo quando esso sarà effettivamente caricato in
ram per la sua esecuzione. La traduzione degli indirizzi da logici a fisici viene fatta mediante un
dispositivo hardware chiamato MMU (Memory Management Unit), sulla base di una tabella di
corrispondenza mantenuta dal modulo di gestione della memoria del SO.
Un meccanismo molto importante gestito da questo modulo è quello della memoria virtuale:
quando la memoria RAM a disposizione non basta per caricare tutti i processi, viene usata una parte
del disco rigido come fosse la RAM, pur sapendo che l’operazione di trasferimento da/verso il disco
è mille volte più lenta di quella della RAM (che è circa 100-1000 volte più lenta del processore).
Questo evita di far si che si verifichino errori per riferimento a istruzioni non presenti in memoria.
Il modulo di gestione della memoria del SO si occupa, oltre che dell’allocazione della RAM per lo
scheduling di lungo termine, anche della gestione della memoria Cache, che viene indirizzata allo
stesso modo della memoria RAM.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Strategie di allocazione della RAM
Gli obiettivi del Long Term Scheduler sono quelli dell’ottimizzazione della memoria, cioè farci
stare il maggior numero possibile di processi, e la protezione dei dati: è di fondamentale importanza
fare in modo che un processo non possa modificare, magari accidentalmente, dati di un altro
processo. Diverse strategie di allocazione sono state proposte:
Partizionamento: in questo schema di allocazione la memoria risulta partizionata in più parti
(che impropriamente in informatica vengono chiamate partizioni), e viene assegnata una diversa
parte a ogni diverso processo. I processi che non trovano spazio restano sul disco (memoria
virtuale). Il SO mantiene una tabella delle partizioni in cui è specificato, per ogni processo,
l’indirizzo iniziale della partizione, e la sua dimensione in byte.
processo1 partizione1 dimensione1
processo2 partizione2 dimensione 2
…
…
…
Con il partizionamento della memoria, le possibili strategie di allocazione della RAM sono first fit
(scegli la prima partizione libera sufficientemente grande), best fit (scegli la partizione più adatta
per dimensioni), e worst fit (scegli la partizione meno adatta). Nel primo caso si produce il
fenomeno della frammentazione della memoria: lo spazio di una partizione che avanza, non
necessaria al processo corrispondente, non è ulteriormente utilizzabile. Nel secondo caso, il
problema della frammentazione viene parzialmente risolto. Il terzo caso, sebbene sembri poco
vantaggioso, ha una sua utilità quando insieme ai programmi occorre includere nella partizione
anche i dati che essi utilizzano: lasciare parecchio spazio nella partizione può avere senso per
evitare di accedere ai dati su disco ogni volta, o di dover suddividere opportunamente lo spazio dei
dati (qualora essi siano memorizzati separatamente dai programi).
Paginazione: in questo schema lo spazio degli indirizzi logici è suddiviso in aree della stessa
dimensione chiamate pagine di circa 4Kbyte. Corrispondentemente, lo spazio degli indirizzi fisici
risulta suddiviso in settori. A ogni processo vengono assegnate più pagine, non necessariamente
contigue, e dunque più settori della RAM. In questo modo, si crea meno frammentazione della
memoria. Gli indirizzi logici sono formati da un indirizzo base più un offset: il primo rappresenta il
numero di pagina, il secondo il numero di byte all’interno della pagina. Mediante una tabella di
paginazione, il SO mantiene la corrispondenza tra pagine e settori, e mediante una tabella dei
settori identifica l’indirizzo fisico di ogni settore.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Il meccanismo della paginazione agevola, inoltre, il meccanismo della memoria virtuale: alcune
pagine di un processo possono essere effettivamente caricate in RAM, mentre altre risiedere ancora
sul disco. Se il processo richiede una pagina non presente in tabella (cioè, si trova sul disco), si ha
un page fault e viene avviata una routine sistema di gestione del fault, che carica in tabella (e in
RAM) la pagina necessaria a scapito di qualche altra pagina (swapping).
Il problema principale della paginazione è legato alla gestione di processi cooperanti mediante
buffer condiviso: un buffer suddiviso in più pagine risulta molto più difficile da gestire a livello di
programmazione. Inoltre, resta il problema della frammentazione interna alle pagine, sebbene
minore rispetto alla frammentazione causata dal partizionamento.
Segmentazione: in questo schema, la memoria RAM risulta suddivisa in segmenti di lunghezza
variabile, ognuno dei quali contiene un elemento ben definito del programma (ad esempio, una
funzione, una variabile, una stringa, ecc.). Per ogni segmento, il SO mantiene in una tabella di
segmentazione l’indirizzo base e la dimensione del segmento.
segmento 1 base1 dimensione1
segmento 2 base2 dimensione2
…
…
…
Di nuovo, la traduzione degli indirizzi da logici a fisici è fatta sommando l’indirizzo base più
l’offset dell’istruzione, come nel caso della paginazione.
Il vantaggio principale di questo schema è quello di eliminare completamente il fenomeno della
frammentazione. Attualmente, i moderni SO utilizzano una tecnica mista di allocazione della
memoria fatta di pagine e segmenti.
5. Il File System
Il terzo modulo del SO di cui ci occupiamo è quello relativo alla gestione dei file. Ricordiamo che
un file è un insieme di informazioni binarie (quindi, bit) memorizzate in modo persistente. A ogni
file il SO associa un insieme di attributi, che ne indicano:
-
il numero progressivo (nella lista dei file aperti);
-
il nome del file e l’estensione (es. pippo.txt, prova.cpp, mioprogramma.exe). L’estensione si
usa solo nei sistemi Windows, mentre per i sistemi Unix-like (Linux, MAC OS) non è
prevista: il SO riconosce il tipo di file in base a un codice (una stringa) posto all’inizio del
file;
-
la sua collocazione (il percorso nella struttura logica dei file);
-
la sua dimensione;
-
i privilegi (protezione): quale utente può fare quale operazione sul file (ad esempio,
creazione, apertura, lettura/scrittura, eliminazione, esecuzione, ecc.);
-
la data di creazione e di ultima modifica (solo ultima modifica in Windows).
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Il File System del SO mantiene in una tabella la lista di file aperti, in cui sono indicati il numero
progressivo del file, un handler (puntatore) che ne specifica la posizione sul disco, l’utente che ha
aperto il file e l’applicazione che ha eseguito l’apertura. Se un nuovo utente apre un altro file,
qualora autorizzato, viene creato un nuovo handler e inserito in tabella.
id1 handler1 user1 application1
id2 handler2 user2 application2
…
…
…
Struttura del file system
I percorsi logici dei file sono organizzati dal file system in una struttura ad albero. Un albero è un
grafo connesso aciclico, in cui un nodo rappresenta la radice dell’albero, e i nodi che non hanno
successori sono chiamati foglie (si pensi a un albero genealogico). La radice dell’albero corrisponde
a un’unità logica di un dispositivo di memorizzazione di massa, i nodi intermedi corrispondo alle
directory (o cartelle), e le foglie corrispondono ai file.
In Windows è possibile avere tante unità logiche (ad esempio, si può partizionare l’hard disk in più
unità C, D, ecc., e poi avere altre unità logiche come E per il CD-ROM, F per la pendrive, ecc.), a
ognuna delle quali corrisponde un diverso albero. Il file di questo documento, ad esempio, si trova
nel percorso d:\documents and settings\tchasqui\didattica\opsis.doc (a partire dalla radice, unità
logica D, scendi nella cartella documents and settings, poi nella cartella tchasqui, poi ancora nella
cartella didattica e lì si trova il file opsis.doc). Si noti come il simbolo \ rappresenta la discesa di un
livello nella struttura.
Nei sistemi Unix-like esiste invece un’unica radice, cioè una sola struttura ad albero per tutti i
dispositivi. Allorché si debba utilizzare un altro dispositivo di memorizzazione, come il floppy disk
o la pendrive, occorre “montare” (mounting) nell’unico albero la struttura del file system del
dispositivo, come in figura seguente:
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Mentre nei sistemi Windows le unità logiche si chiamano C: , D: , E: ecc., in Unix la sola unità
logica alla radice è indicata con il simbolo /, che è anche il simbolo che si usa per scendere di
livello. Ad esempio, il percorso del file prova.cpp che si trova nella directory bin è indicato con
/bin/prova.cpp. In entrambi i tipi di sistemi, sia Windows che Unix, l’operatore .. può essere usato
per risalire la struttura di un livello nei percorsi relativi (a partire da un nodo intermedio).
Ad ogni nodo dell’albero (o degli alberi, in Windows), sia che si tratti di un nodo intermedio
(directory) sia che si tratti di una foglia (file), il SO associa un Access Control List (ACL) che
definisce i privilegi degli utenti per quel nodo. In Unix, l’ACL è composto di una lettera per
specificare se si tratta di un file o una directory, e poi da tre gruppi di tre lettere che indicano i
privilegi di lettura/scrittura/esecuzione a livello utente, gruppo o generale. Ad esempio,
d
rw_
r_ _
_
rwx
rw_
r_ _
_ __
directory con privilegi di lettura e scrittura per
l’utente, solo lettura per il gruppo e per tutti gli
altri
file con privilegi di lettura, scrittura ed
esecuzione a livello utente, lettura e scrittura a
livello gruppo, e nessuna operazione per tutti
gli altri
In Windows esistono due tipi di file system: FAT (File Allocation Table) e NTFS (New Technology
File System). Il primo è il più vecchio dei due (usato solo fino a Win95), e non prevede
informazioni ACL (infatti, tutti i SO di casa Microsoft fino a Win95 non prevedono la multiutenza).
Questo è il motivo per cui se abbiamo nel nostro computer due sistemi operativi come Windows e
Linux, riusciamo a vedere in Linux i file di Windows solo se abbiamo usato il sistema NTFS.
Allocazione fisica dei file
Finora abbiamo parlato di percorsi logici dei file: sono quelli che vedono gli utenti e i programmi
che a questi file devono accedere. In realtà, la situazione a livello fisico è molto diversa: il disco
rigido è formato da tanti dischi magnetici montati su un unico perno centrale, ognuno dei quali
risulta suddiviso in tracce e settori. L’intersezione tra una traccia e un settore si chiama blocco e ha
di solito la dimensione di 64Kbyte; più blocchi allineati sui vari dischi danno luogo a un cilindro.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
Ogni file è memorizzato su uno o più blocchi, ed è il SO che mantiene la corrispondenza tra i
percorsi logici dei file, più agevoli per gli utenti, e i percorsi fisici veri e propri (quale disco, quale
cilindro, quale blocco). Ma in che modo il SO assegna i blocchi ai diversi file? Esistono diverse
strategie di allocazione del disco:
1) allocazione contigua: vengono assegnati al file blocchi adiacenti tra loro. Questa strategia
minimizza i tempi di trasferimento dei file, in quanto rende minimo il movimento
meccanico necessario per posizionarsi sui byte di interesse. I blocchi adiacenti possono
trovarsi sullo stesso cilindro (nessun movimento), oppure sulla stessa traccia (movimento di
rotazione del disco) oppure sullo stesso settore (spostamento delle testine).
2) allocazione collegata: i blocchi vengono collegati tra loro memorizzando su ogni blocco
l’indirizzo del blocco successivo, creando così una lista lineare del tipo
in questo tipo di allocazione, qualunque blocco può essere utilizzato per ogni file, e non si
verifica così il problema della frammentazione del disco che, invece, si ha nell’allocazione
contigua. Tuttavia, richiede parecchi movimenti (rotazione del disco e spostamento delle
testine) per passare da un blocco a un altro, con conseguente perdita di velocità di
trasferimento dei dati.
3) allocazione indicizzata: il primo blocco viene utilizzato come indice per memorizzare gli
indirizzi fisici dei blocchi che costituiscono il file. E’ più facile da gestire rispetto
all’allocazione collegata, ma presenta gli stessi problemi di velocità di trasferimento.
informaticangioy.altervista.org
Sistemi Operativi
A.S. 2009/2010
I comandi per il file system
Anche se i nostri moderni sistemi operativi, essendo user-friendly, ci mettono a disposizione
l’interfaccia WIMP per la gestione dei file (gestione risorse, doppio click su una cartella per vedere
il suo contenuto, ecc.), esiste una serie di comandi che è possibile dare al SO per lavorare con il file
system. In Windows, occorre aprire una finestra DOS per dare questi comandi (menu avvio 
esegui  cmd oppure menu avvio  programmi accessori  prompt di MS DOS), mentre in
Linux o MAC bisogna aprire una shell (finestra di comando: la più usata è bash).
Riportiamo, a titolo di esempio, alcuni dei comandi di principali, per la sintassi e le modalità di
utilizzo dei quali rimandiamo a manuali specifici.
WINDOWS
UNIX
CD
CD
Change directory
DIR
LS
Directory listing
COPY
CP
File copy
MOVE
MV
Move file/directory
DEL/RMDIR
RM
Remove file/directory
MKDIR
MD
Make directory
HELP
HELP
Help commands
TREE
LS
View subtree
ATTRIB
CHMOD
View/change file attributes