Torna alla pagina di Sistemi Operativi
:: Appunti caotici ::
Lezione 2
Creazione e terminazione dei processi
Pag 1
Sommario
...
Pag 2
Processi come flussi di operazioni
...
Modellazione della computazione a processi
I modelli di computazione non implicano nulla a livello di struttura del codice del programma, e si dividono in:
- processi monolitici, dove il programma fa tutte le operazioni dall'inizio alla fine con un unico flusso (e quindi processo)
- processi cooperativi, dove il programma lancia una serie di processi concorrenti che lavorano (a livello logico) in parallelo per lo stesso scopo. Da notare come non lavorino in modo indipendente, ma interagendo e quindi condividendo risultati, sincronizzandosi, ecc.
Modelli di realizzazione del codice eseguibile:
- programma monolitico
- programmi separati, in cui bisogna pensare il codice fisicamente separato, composto da un ventaglio di programmi ognuno con la sua parte. Quindi la prima operazione che eseguirà l'applicazione generale sarà lanciare i vari programmi che la compongono
Pag 3
Generazione di un processo
La fork() crea un processo indipendente ed eventualmente cooperante. Sostanzialmente genera due flussi:
- quello del processo padre P, che continua
- quello del processo figlio Q, che viene generato
Non c'è nulla che impedisca a P e Q di creare altri figli in qualsiasi momento.
Risorse dei processi
Il processo figlio avrà una propria porzione di memoria centrale separata da quella del padre. In particolare sarà separato il contenuto dello stack pointer, il che è una condizione necessaria perché i due processi siano indipendenti (altrimenti starebbero eseguendo le stesse operazioni nello stesso momento).
Il processo padre può condividere tutte o parte (alcune o nessuna) delle sue risorse col figlio. Nel caso in cui il processo figlio non condividesse nulla col padre, dovrà ottenere le risorse esclusivamente dal sistema.
Infine, il processo padre può inizializzare i dati di Q, in modo tale da definire l'ambiente operativo iniziale in cui il figlio andrà ad operare.
Pag 4
Spazio di indirizzamento (1)
Lo spazio di memoria del processo figlio è riservato. Ciò garantisce una turnazione adeguata dei processi sul processore, dal momento che nessuno di essi potrà interferire nella memoria centrale dell'altro.
Per quanto riguarda la parte di codice, a livello logico è sdoppiato sulle due porzioni di memoria di P e di Q. In realtà tale separazione è spesso solo illusoria: a patto che il codice non cambi, ne esiste un'unica copia da cui padri e figli attingono. Quindi ciò non è vero per programmi scritti con linguaggi come il LISP o il PROLOG, in grado di modificare il loro codice in fase di esecuzione.
Spazio di indirizzamento (2)
...
Pag 5
Spazio di indirizzamento (3)
La exec() viene utilizzata per creare un nuovo programma, quindi con un suo spazio di memoria indipendente, che butta via l'ambiente del padre e ne carica uno nuovo.
Nel caso si voglia ottenere un nuovo programma, la funzione exec() va eseguita come prima istruzione del processo figlio
La fork() e la exec() vengono generalmente tenute separate (e non facenti parte di un'unica suppafunction) perché potrebbero essere utilizzate per effettuare altre operazioni, come ad esempio cambiare il codice che si sta eseguendo per svolgere attività di tipo diverso (cambiando così il codice eseguibile).
Esempio
...
Pag 6
Esecuzione dei processi
...
Albero dei processi
Ho un processo iniziale che attiva altri processi, che a loro volta attivano altri processi, che .. ecc ecc
L'albero rappresentato fa riferimento ad un tipico sistema operativo di tipo Unix: il sistema parte, viene inizializzato, viene eseguito il processo cosiddetto 0 che crea una serie di procedure di sistema standard, tra cui il processo init che gestisce a sua volta i processi cui compete l'interfaccia con l'utente (interprete comandi); poi l'utente può lanciare vari processi che lanciano ecc ecc
Nota: la catena di eventi vista sopra non avviene solo nei sistemi Unix, ma in modo più o meno standard anche negli altri sistemi operativi (solo, con nomi diversi).
Pag 7
Terminazione di un processo (1)
Normalmente il processo termina dopo l'esecuzione dell'ultima istruzione del codice (inteso ad alto livello).
La exit() è una funzione che termina formalmente il programma restituendo al sistema operativo un valore di ritorno (che indica la buonriuscita del programma) e dealloca le risorse. Nel caso in cui la funzione non vada a buon fine, l'errore si propagherà dal valore di ritorno che attiverà funzioni di avviso dell'utente ed eventuale gestione dell'errore.
Terminazione di un processo (2)
La funzione abort() è utilizzata per la terminazione con anomalie.
Tra le possibili cause che conducono al suo utilizzo ricordiamo:
- eccessivo uso di una risorsa, ad esempio una massiccia richiesta di allocazione di variabili dinamiche (che vanno presto a saturare lo spazio disponibile)
- terminazione a cascata, nel senso che se uccido un processo i figlio potrebbero essere uccisi a loro volta.
Torna alla pagina di Sistemi Operativi