Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Introduzione ai sistemi operativi

Ehi Habr! Vorrei portare alla vostra attenzione una serie di articoli-traduzioni di una letteratura interessante secondo me - OSTEP. Questo materiale discute in modo abbastanza approfondito il lavoro dei sistemi operativi simili a Unix, vale a dire lavorare con processi, vari programmatori, memoria e altri componenti simili che compongono un sistema operativo moderno. Puoi vedere l'originale di tutti i materiali qui qui. Si prega di notare che la traduzione è stata fatta in modo non professionale (abbastanza liberamente), ma spero di aver mantenuto il significato generale.

Il lavoro di laboratorio su questo argomento può essere trovato qui:

Altre parti:

Puoi anche dare un'occhiata al mio canale su telegramma =)

Diamo un'occhiata all'astrazione più fondamentale che il sistema operativo fornisce agli utenti: il processo. La definizione del processo è abbastanza semplice: lo è programma in esecuzione. Il programma stesso è una cosa senza vita situata sul disco: è un insieme di istruzioni e possibilmente alcuni dati statici in attesa di essere avviati. È il sistema operativo che prende quei byte e li esegue, trasformando il programma in qualcosa di utile.
Molto spesso, gli utenti desiderano eseguire più di un programma contemporaneamente, ad esempio è possibile eseguire un browser, un gioco, un lettore multimediale, un editor di testo e simili sul proprio laptop. In effetti, un tipico sistema può eseguire decine o centinaia di processi contemporaneamente. Questo fatto rende il sistema più facile da usare, non devi mai preoccuparti se la CPU è libera, devi solo eseguire i programmi.

Ciò solleva il problema: come fornire l'illusione di molte CPU? Come può il sistema operativo creare l'illusione di un numero quasi infinito di CPU, anche se si dispone di una sola CPU fisica?

Il sistema operativo crea questa illusione attraverso la virtualizzazione della CPU. Avviando un processo, quindi arrestandolo, avviandone un altro e così via, il sistema operativo può mantenere l'illusione che esistano molte CPU virtuali, quando in realtà ci saranno uno o più processori fisici. Questa tecnica si chiama divisione delle risorse della CPU per tempo. Questa tecnica consente agli utenti di eseguire tutti i processi simultanei che desiderano. Il costo di questa soluzione è legato alle prestazioni, poiché se la CPU è condivisa da più processi, ogni processo verrà elaborato più lentamente.
Per implementare la virtualizzazione della CPU, e soprattutto per farlo bene, il sistema operativo necessita di supporto sia di basso che di alto livello. Viene chiamato il supporto di basso livello meccanismi sono metodi o protocolli di basso livello che implementano la parte richiesta della funzionalità. Un esempio di tale funzionalità è il cambio di contesto, che offre al sistema operativo la possibilità di interrompere un programma ed eseguirne un altro sul processore. Questa divisione del tempo è implementata in tutti i moderni sistemi operativi.
Oltre a questi meccanismi c’è una logica integrata nel sistema operativo, sotto forma di “politiche”. Politica è un certo algoritmo decisionale per il sistema operativo. Tali politiche, ad esempio, decidono quale programma deve essere avviato per primo (da un elenco di comandi). Quindi, ad esempio, questo problema sarà risolto da una politica chiamata pianificatore (politica di pianificazione) e quando si sceglie una soluzione, sarà guidato da dati quali: cronologia di avvio (quale programma è stato avviato più a lungo negli ultimi minuti), quale carico trasporta questo processo (quali tipi di programmi sono stati avviati), parametri di prestazione (se il sistema è ottimizzato per l'interazione interattiva o per il throughput) e così via.

Astrazione: processo

L'astrazione di un programma in esecuzione eseguito dal sistema operativo è ciò che chiamiamo processo. Come accennato in precedenza, un processo è semplicemente un programma in esecuzione, in qualsiasi periodo di tempo istantaneo. Un programma con il quale possiamo ottenere informazioni riassuntive da varie risorse di sistema a cui questo programma accede o influenza durante la sua esecuzione.
Per comprendere le componenti del processo è necessario comprendere gli stati del sistema: ciò che il programma può leggere o modificare durante il suo funzionamento. In ogni momento è necessario capire quali elementi del sistema sono importanti per l'esecuzione del programma.
Uno degli elementi ovvi dello stato di sistema che il processo include è memoria. Le istruzioni si trovano nella memoria. Anche i dati che il programma legge o scrive si trovano nella memoria. Pertanto, la memoria che un processo può indirizzare (chiamata spazio degli indirizzi) è parte del processo.
Fanno parte dello stato del sistema anche i registri. Molte istruzioni mirano a modificare il valore dei registri o a leggerne il valore, e quindi anche i registri diventano una parte importante del funzionamento del processo.
È da notare che lo stato macchina è formato anche da alcuni registri speciali. Per esempio, IP - puntatore di istruzioni — un puntatore all'istruzione che il programma sta attualmente eseguendo. C'è anche puntatore dello stack e ad esso correlato puntatore a cornice, che servono per gestire: parametri di funzione, variabili locali e indirizzi di ritorno.
Infine, i programmi spesso accedono alla ROM (memoria di sola lettura). Queste informazioni "I/O" (input/output) dovrebbero includere un elenco di file attualmente aperti dal processo.

API di processo

Per migliorare la nostra comprensione del funzionamento del processo, studiamo esempi di chiamate di sistema che dovrebbero essere incluse in qualsiasi interfaccia del sistema operativo. Queste API sono disponibili in una forma o nell'altra su qualsiasi sistema operativo.

Creare (creazione): il sistema operativo deve includere un metodo che consenta di creare nuovi processi. Quando si immette un comando nel terminale o si avvia un'applicazione facendo doppio clic su un'icona, viene inviata una chiamata al sistema operativo per creare un nuovo processo e quindi avviare il programma specificato.
Rimozione: Poiché esiste un'interfaccia per la creazione di un processo, il sistema operativo dovrebbe fornire anche la possibilità di forzare la rimozione di un processo. La maggior parte dei programmi si avvierà e terminerà naturalmente da sola durante l'esecuzione. Altrimenti l'utente vorrebbe poterli uccidere e quindi sarebbe utile un'interfaccia per fermare il processo.
Aspetta! (in attesa): a volte è utile attendere il completamento di un processo, quindi vengono fornite alcune interfacce che forniscono la possibilità di attendere.
Controllo vario (vari controlli): oltre all'uccisione e all'attesa del processo, esistono anche altri metodi di controllo. Ad esempio, la maggior parte dei sistemi operativi prevede la possibilità di bloccare un processo (interromperne l'esecuzione per un certo periodo) e poi riprenderlo (continuare l'esecuzione)
Stato dei servizi (stato): esistono varie interfacce per ottenere alcune informazioni sullo stato di un processo, ad esempio da quanto tempo è in esecuzione o in quale stato si trova attualmente.

Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Creazione del processo: dettagli

Una delle cose interessanti è come esattamente i programmi vengono trasformati in processi. Soprattutto il modo in cui il sistema operativo rileva ed esegue il programma. Come viene creato esattamente il processo.
Prima di tutto, il sistema operativo deve caricare in memoria (nello spazio degli indirizzi del processo) il codice del programma e i dati statici. I programmi si trovano solitamente su un disco o un'unità SSD in un formato eseguibile. Pertanto, il processo di caricamento del programma e dei dati statici in memoria richiede che il sistema operativo sia in grado di leggere quei byte dal disco e posizionarli da qualche parte nella memoria.

Nei primi sistemi operativi, il processo di caricamento veniva eseguito con entusiasmo, il che significa che l'intero codice veniva caricato in memoria prima dell'avvio del programma. I moderni sistemi operativi lo fanno pigramente, caricando cioè pezzi di codice o dati solo quando il programma li richiede durante la sua esecuzione.

Una volta caricati il ​​codice e i dati statici nella memoria del sistema operativo, è necessario eseguire alcune altre operazioni prima che il processo possa essere eseguito. È necessario allocare una certa quantità di memoria per lo stack. I programmi utilizzano lo stack per variabili locali, parametri di funzione e indirizzi di ritorno. Il sistema operativo alloca questa memoria e la fornisce al processo. Lo stack può anche essere allocato con alcuni argomenti, nello specifico riempie i parametri della funzione main(), ad esempio con un array di argc e argv.

Il sistema operativo potrebbe anche allocare memoria nell'heap del programma. L'heap viene utilizzato dai programmi per richiedere esplicitamente dati allocati dinamicamente. I programmi richiedono questo spazio chiamando la funzione malloc () e lo cancella esplicitamente chiamando la funzione gratuito(). L'heap è necessario per strutture dati come fogli collegati, tabelle hash, alberi e altro. Inizialmente, una piccola quantità di memoria viene allocata all'heap, ma col tempo, durante l'esecuzione del programma, l'heap può richiedere più memoria tramite la chiamata API della libreria malloc(). Il sistema operativo è coinvolto nel processo di allocazione di più memoria per soddisfare queste richieste.

Il sistema operativo eseguirà anche attività di inizializzazione, in particolare quelle relative all'I/O. Ad esempio, sui sistemi UNIX, ogni processo per impostazione predefinita ha 3 descrittori di file aperti, per input standard, output ed errore. Queste maniglie consentono ai programmi di leggere l'input dal terminale e di visualizzare le informazioni sullo schermo.

Pertanto, caricando codice e dati statici in memoria, creando e inizializzando lo stack ed eseguendo altre attività relative all'esecuzione di attività di I/O, il sistema operativo prepara la fase per l'esecuzione del processo. Infine, rimane un ultimo compito: eseguire il programma attraverso il suo punto di ingresso, chiamato funzione main(). Eseguendo la funzione main(), il sistema operativo trasferisce il controllo della CPU al processo appena creato, quindi il programma inizia l'esecuzione.

Stato del processo

Ora che abbiamo una certa comprensione di cos'è un processo e di come viene creato, elenchiamo gli stati del processo in cui può trovarsi. Nella sua forma più semplice, un processo può trovarsi in uno di questi stati:
corsa. Durante l'esecuzione, il processo viene eseguito sul processore. Ciò significa che le istruzioni vengono eseguite.
Pronto. Nello stato pronto, il processo è pronto per essere eseguito, ma per qualche motivo il sistema operativo non lo esegue all'ora specificata.
bloccato. Nello stato bloccato, un processo esegue alcune operazioni che gli impediscono di essere pronto per l'esecuzione finché non si verifica un evento. Un esempio comune è quando un processo avvia un'operazione di I/O, viene bloccato in modo che qualche altro processo possa utilizzare il processore.

Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Puoi immaginare questi stati sotto forma di grafico. Come possiamo vedere nell'immagine, lo stato del processo può cambiare tra RUNNING e READY a discrezione del sistema operativo. Quando lo stato di un processo cambia da PRONTO a IN ESECUZIONE, significa che il processo è stato pianificato. Nella direzione opposta: rimosso dal layout. Nel momento in cui un processo diventa BLOCCATO, ad esempio, avvio un'operazione di IO, il sistema operativo lo manterrà in questo stato finché non si verifica qualche evento, ad esempio il completamento dell'IO. in questo momento avviene il passaggio allo stato READY ed eventualmente immediatamente allo stato RUNNING se il sistema operativo lo decide.
Diamo un'occhiata ad un esempio di come due processi si muovono attraverso questi stati. Per cominciare, immaginiamo che entrambi i processi siano in esecuzione e che ciascuno utilizzi solo la CPU. In questo caso, i loro stati appariranno così.

Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Nell'esempio seguente, il primo processo, dopo un po' di tempo in esecuzione, richiede IO ed entra nello stato BLOCCATO, consentendo l'esecuzione di un altro processo (FIG 1.4). Il sistema operativo rileva che il processo 0 non sta utilizzando la CPU e avvia il processo 1. Mentre il processo 1 è in esecuzione, l'IO viene completato e lo stato del processo 0 cambia in READY. Infine, il processo 1 è stato completato e, al termine, il processo 0 avvia, esegue e termina il suo lavoro.

Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Struttura dati

Il sistema operativo stesso è un programma e, proprio come qualsiasi altro programma, dispone di alcune strutture dati chiave che tengono traccia di varie informazioni rilevanti. Per tenere traccia dello stato di ciascun processo, il sistema operativo ne supporterà alcuni elenco dei processi per tutti i processi nello stato PRONTO e alcune informazioni aggiuntive per tenere traccia dei processi attualmente in esecuzione. Inoltre, il sistema operativo dovrebbe monitorare i processi bloccati. Una volta completata l'I/O, il sistema operativo deve riattivare il processo richiesto e metterlo in uno stato pronto per l'esecuzione.

Ad esempio, il sistema operativo deve preservare lo stato dei registri del processore. Nel momento in cui il processo si interrompe, lo stato dei registri viene memorizzato nello spazio degli indirizzi del processo e nel momento in cui il suo funzionamento continua, i valori dei registri vengono ripristinati e quindi continua l'esecuzione di questo processo.

Oltre agli stati pronto, bloccato e in esecuzione, esistono altri stati. A volte, al momento della creazione, un processo potrebbe trovarsi nello stato INIT. Infine, un processo può essere posto nello stato FINALE quando è già stato completato, ma le sue informazioni non sono ancora state cancellate. Sui sistemi UNIX questo stato viene chiamato processo zombie. Questo stato è utile nei casi in cui un processo genitore desidera conoscere il codice di ritorno di un figlio, ad esempio, solitamente 0 segnala un successo e 1 un errore, ma i programmatori possono emettere codici di output aggiuntivi per segnalare problemi diversi. Quando il processo genitore termina, effettua un'ultima chiamata di sistema, come wait(), per attendere che il processo figlio termini e segnali al sistema operativo che può cancellare tutti i dati associati al processo terminato.

Sistemi operativi: tre pezzi facili. Parte 2: Astrazione: processo (traduzione)

Punti chiave della lezione:

Процесс — l'astrazione principale di un programma in esecuzione nel sistema operativo. In qualsiasi momento, un processo può essere descritto dal suo stato: il contenuto della memoria nel suo spazio di indirizzi, il contenuto dei registri del processore, inclusi il puntatore alle istruzioni e il puntatore allo stack, e le informazioni IO, come i file aperti letti o scritti.
API di processo consiste in chiamate che i programmi possono effettuare ai processi. In genere si tratta di chiamate di creazione, eliminazione o di altro tipo.
● Il processo è in uno dei tanti stati, tra cui in esecuzione, pronto, bloccato. Vari eventi come la pianificazione, le eccezioni alla pianificazione o le attese possono modificare lo stato di un processo dall'uno all'altro.
Elenco dei processi contiene informazioni su tutti i processi nel sistema. Ogni voce in esso contenuta è chiamata blocco di controllo del processo, che in realtà è una struttura che contiene tutte le informazioni necessarie su un processo specifico. 

Fonte: habr.com

Aggiungi un commento