Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

Introduzione ai sistemi operativi

Ciao, Habr! Voglio presentarvi una serie di articoli-traduzioni di una letteratura che considero interessante: OSTEP. Questo materiale analizza approfonditamente il funzionamento dei sistemi operativi simili a Unix, in particolare il lavoro con i processi, diversi scheduler, la memoria e altre componenti simili che costituiscono un moderno sistema operativo. L'originale di tutti i materiali può essere trovato qui qui. Si prega di notare che la traduzione non è stata eseguita da un professionista (è abbastanza libera), ma spero di aver mantenuto il significato generale.

Le esercitazioni su questo argomento possono essere trovate qui:
— originale: pages.cs.wisc.edu/~remzi/OSTEP/Homework/homework.html
— originale: github.com/remzi-arpacidusseau/ostep-code
— mia personale adattazione: github.com/bykvaadm/OS/tree/master/ostep

E potete anche dare un'occhiata al mio canale su Telegram =)

Funzionamento del programma

Cosa succede quando funziona un programma? Il programma esegue una semplice operazione: esegue istruzioni. Ogni secondo, milioni, e forse anche miliardi di istruzioni vengono estratte dalla memoria RAM dal processore, il quale le decodifica (ad esempio, riconosce a quale tipo appartengono) ed esegue. Queste possono essere l'addizione di due numeri, accesso alla memoria, verifica di una condizione, passaggio a una funzione, e così via. Dopo aver completato un'istruzione, il processore passa all'esecuzione della successiva. E così via, istruzione dopo istruzione, fino a quando il programma non termina.
Questo esempio è ovviamente semplificato: in realtà, per accelerare il lavoro del processore, l'hardware moderno consente di eseguire le istruzioni fuori ordine, prevedere risultati possibili, eseguire istruzioni simultaneamente e altre astuzie simili.

Modello di calcolo di von Neumann

La forma semplificata di lavoro che abbiamo descritto è simile al modello di calcolo di von Neumann. Fon-Neiman è uno dei pionieri dei sistemi informatici ed è anche uno degli autori della teoria dei giochi.Durante l'esecuzione del programma si verificano anche molti altri eventi, funzionano numerosi altri processi e logiche esterne, il cui obiettivo principale è semplificare avvio, funzionamento e manutenzione del sistema.
Esiste un insieme di software responsabile della facilità di esecuzione dei programmi (o addirittura che permette l'esecuzione di più programmi contemporaneamente), che consente ai programmi di condividere la stessa memoria e di interagire con vari dispositivi. Questo insieme di software è fondamentalmente ciò che chiamiamo sistema operativo, e uno dei suoi compiti è monitorare il corretto e efficiente funzionamento del sistema, oltre a garantire la facilità di gestione di questo sistema.

Il sistema operativo

Il sistema operativo, abbreviato in SO, è un insieme di programmi interconnessi, progettati per gestire le risorse del computer e organizzare l'interazione dell'utente con il computer..
Il SO raggiunge la sua efficienza principalmente attraverso la tecnica più importante: la tecnica di virtualizzazione.. Il sistema operativo interagisce con la risorsa fisica (processore, memoria, disco e simili) e la trasforma in una forma più generale, con maggiori capacità e più semplice da usare. Pertanto, per una comprensione generale, si può molto grossolanamente confrontare il sistema operativo con una macchina virtuale.
Per consentire agli utenti di dare comandi al sistema operativo e quindi sfruttare le capacità della macchina virtuale (come: avviare un programma, allocare memoria, accedere a un file e così via), il sistema operativo fornisce un'interfaccia chiamata API (application programming interface) alla quale si possono fare chiamate (call). Un tipico sistema operativo permette di fare centinaia di chiamate di sistema.
Infine, poiché la virtualizzazione consente a più programmi di operare (condividendo così la CPU), accedendo contemporaneamente alle loro istruzioni e dati (condividendo così la memoria) e accedendo ai dischi (condividendo così i dispositivi di input/output), il sistema operativo è anche chiamato gestore delle risorse. Ogni processore, disco e memoria sono risorse di sistema e così uno dei compiti del sistema operativo diventa la gestione di queste risorse, facendo ciò in modo efficiente, equo o, al contrario, a seconda del compito per il quale questo sistema operativo è stato progettato.

Virtualizzazione della CPU

Consideriamo il seguente programma:
(https://www.youtube.com/watch?v=zDwT5fUcki4&feature=youtu.be)

Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

Non esegue azioni particolari, in sostanza tutto ciò che fa è chiamare la funzione spin(), il cui compito è controllare ciclicamente il tempo e restituire, dopo che è trascorsa un secondo. Così, ripete all'infinito la stringa che l'utente ha passato come argomento.
Avvieremo questo programma e gli passeremo come argomento il simbolo “A”. Il risultato non è particolarmente interessante: il sistema esegue semplicemente un programma che periodicamente stampa a schermo il simbolo “A”.
Ora proviamo una variante in cui sono avviate molteplici istanze dello stesso programma, ma che stampano lettere diverse, per rendere il concetto più chiaro. In questo caso, il risultato sarà leggermente diverso. Nonostante abbiamo un solo processore, i programmi vengono eseguiti contemporaneamente. Com'è possibile? La risposta è che il sistema operativo, con l'aiuto delle capacità hardware, crea un'illusione. Un'illusione che nella macchina ci siano più processori virtuali, trasformando un singolo processore fisico in un numero teoricamente infinito, permettendo così alle applicazioni di sembrare che vengano eseguite simultaneamente. Questa illusione è chiamata Virtualizzazione della CPU.
Una situazione del genere genera molte domande, ad esempio, se più programmi desiderano avviarsi contemporaneamente, quale verrà eseguito? Questo interrogativo è gestito dalle “politiche” del sistema operativo. Le politiche vengono utilizzate in molti aspetti del sistema operativo e rispondono a domande come questa, oltre a fungere da meccanismi di base che il sistema operativo implementa. Da qui deriva il ruolo del sistema operativo come gestore delle risorse.

Virtualizzazione della memoria

Ora esaminiamo la memoria. Il modello fisico della memoria nei moderni sistemi è rappresentato come un insieme di byte. Per leggere dalla memoria è necessario specificare l'indirizzo della cella, per accedervi. Per scrivere o aggiornare i dati, è necessario specificare anche i dati e l'indirizzo della cella in cui registrarli.
L'accesso alla memoria avviene costantemente durante l'esecuzione del programma. Il programma memorizza nella memoria l'intera sua struttura dati e vi accede eseguendo diverse istruzioni. Le istruzioni, nel frattempo, sono anch'esse conservate in memoria, pertanto l'accesso ad essa avviene per ogni richiesta alla prossima istruzione.

Chiamata malloc()

Consideriamo il seguente programma che alloca un'area di memoria utilizzando la chiamata malloc() (https://youtu.be/jnlKRnoT1m0):

Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

Il programma esegue diverse operazioni. Innanzitutto, allocca una certa quantità di memoria (riga 7), quindi stampa l'indirizzo della cella allocata (riga 9) e scrive zero nel primo slot di memoria allocata. Successivamente, il programma entra in un ciclo nel quale incrementa il valore memorizzato all'indirizzo contenuto nella variabile "p". Inoltre, visualizza l'identificativo del proprio processo. L'identificativo di processo è unico per ogni processo in esecuzione.. Se avviamo più copie, ci imbatteremo in un risultato interessante: nel primo caso, se non facciamo nulla e semplicemente eseguiamo più copie, gli indirizzi saranno diversi. Ma questo non rientra nella nostra teoria! Infatti, nei moderni distribuzioni è attiva di default la funzione di randomizzazione della memoria. Se la disattiviamo, otterremo il risultato atteso: gli indirizzi di memoria di due programmi che operano contemporaneamente coincideranno.

Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

In definitiva, risulta che due programmi indipendenti lavorano con i propri spazi di indirizzamento privati, che a loro volta vengono mappati dal sistema operativo nella memoria fisica.Pertanto, l'uso degli indirizzi di memoria all'interno di un singolo programma non influenzerà in alcun modo gli altri, e ogni programma sembra avere a disposizione il proprio blocco di memoria fisica, completamente dedicato a esso. La realtà, tuttavia, è che la memoria fisica è una risorsa condivisa, la cui gestione è svolta dal sistema operativo.

Coerenza

Un altro tema importante nell'ambito dei sistemi operativi è la coerenza. Questo termine è utilizzato quando si parla di problemi nel sistema che possono sorgere quando si lavora su molte cose contemporaneamente all'interno di un singolo programma. I problemi di coerenza si verificano anche all'interno dello stesso sistema operativo. Negli esempi precedenti riguardanti la virtualizzazione della memoria e del processore, abbiamo capito che il sistema operativo gestisce molte cose contemporaneamente: avvia un primo processo, poi un secondo e così via. Si è scoperto che questo comportamento può portare ad alcuni problemi. Ad esempio, i programmi multithreading moderni affrontano tali difficoltà.

Consideriamo il seguente programma:

Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

Il programma nella funzione principale crea due thread, utilizzando la chiamata Pthread_create(). In questo esempio, possiamo pensare al thread come a una funzione eseguita in uno spazio di memoria accanto ad altre funzioni, con il numero di funzioni in esecuzione contemporaneamente chiaramente superiore a uno. In questo caso, ogni thread avvia e esegue la funzione worker() che a sua volta semplicemente incrementa una variabile,.

Avviamo questo programma con l'argomento 1000. Come già potreste immaginare, il risultato dovrebbe essere 2000, poiché ogni thread ha incrementato la variabile 1000 volte. Tuttavia, non è così semplice. Proviamo a eseguire il programma con un numero di ripetizioni molto maggiore.

Sistemi Operativi: Tre Facili Parti. Parte 1: Introduzione

Fornendo un numero come input, ad esempio 100000, ci aspettiamo di vedere come output il numero 200000. Tuttavia, eseguendo ripetutamente il numero 100000, non solo non vediamo la risposta corretta, ma otteniamo anche risposte diverse e sbagliate. Il mistero risiede nel fatto che per incrementare un numero sono necessarie tre operazioni: estrarre il numero dalla memoria, incrementarlo e poi scrivere di nuovo il numero. Poiché tutte queste istruzioni non vengono eseguite in modo atomico (tutte contemporaneamente), possono verificarsi situazioni strane. Questo problema è conosciuto in programmazione condizione di gara — stato di competizione. Quando forze sconosciute in momenti imprecisati possono influenzare l'esecuzione delle vostre operazioni.

Fonte: habr.com

Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster