next up previous contents index return to home!
Next: Caricamento di un programma Up: Processi Previous: Esercizio   Indice   Indice analitico


Terminazione dei processi

Abbiamo visto come sia possibile creare un nuovo processo tramite la syscall fork, occupiamoci ora della terminazione dei processi.

Come spiegato nel capitolo 2, un processo può terminare esplicitamente tramite la syscall _exit(), o la library call exit(), o implicitamente quando l'esecuzione del main termina (ciò può avvenire percé il flusso di esecuzione è arrivato alla fine della funzione main() o perché essa ha effettuato una return).

La corretta terminazione di un processo presuppone che esso ritorni un valore tramite la funzione exit() o l'istruzione return; tale valore può essere recuperato dal processo padre per determinare l'esito dell'esecuzione del figlio. Per fare questo, il padre ha bisogno di sincronizzarsi col figlio, attendendo la sua terminazione tramite una primitiva della famigla wait(). La più semplice di tali funzioni è la wait(), che permette ad un processo di attendere la terminazione di uno dei suoi processi figli, recuperando il valore di uscita ritornato dalla funzione exit(). Ecco quindi come funziona la wait():

Il prototipo della syscall è il seguente:



#include<sys/types.h>
#include<sys/wait.h>

pid_t wait(int *status);


Argomenti in ingresso :

status
- Puntatore ad un intero in cui registrare lo stato di iscita del processo figlio.

Valore restituito :

-1
- Se il processo non ha figli
pid
- Il PID di un processo figlio terminato.

Un esempio tipico di utilizzo della wait() è il seguente:

Esempio

Il valore di ritorno di un processo in generale risponde ad alcune convenzioni di base: come detto, un valore negativo è segno di una terminazione anomala. Per poter analizzare tali valori di ritorno, il sistema mette a disposizione alcune macro: WIFEXITED, WIFSIGNALED e WIFSTOPPED. La macro WIFEXITED applicata al valore status ritorna 1 se il processo figlio è terminato correttamente (ed in questo caso, WEXITSTATUS ottiene il valore >= 0 ritornato dal figlio). Le macro WIFSIGNALED e WIFSTOPPED indicano invece se il processo figlio è stato interrotto da un segnale o è stato bloccato; in questo caso, le macro WTERMSIG e WSTOPSIG permettono di ottenere il numero del segnale che ha terminato o bloccato il processo (vedi Sezione 5.1. In alcuni sistemi è anche definita la macro WSTOPSIG, per vedere se è avvenuto un core dump, con conseguente generazione del file core. Si invita a consultare le man page per avere maggiori informazioni su tali macro e su altre eventualmente definite.

Per permettere la sincronizzazione ed il passaggio del valore di ritorno come specificato precedentemente, il kernel deve mantenere informazioni relative ai processi anche dopo la loro terminazione, finché il loro processo padre non effettua una wait(). Questi processi inattivi che continuano ad occupare posto nella tabella dei processi, detti processi zombie, possono causare un inutile spreco di descrittori dei processi. Per tale motivo, è sempre bene effettuare una wait() su tutti i processi figli creati.

Quando un processo termina, tutti i suoi processi figli (compresi quelli che sono nello stato di zombie) vengono ereditati dal processo di sistema init (in pratica, init diventa automagicamente il padre di tutti i processi il cui padre termina). Questo meccanismo permette di evitare la creazione di un eccessivo numero di processi zombie, in quanto quando un processo figlio di init termina, init effettua automaticamente una wait (nella Sezione 5.1, parlando dei segnali, vedremo come è possibile fare ciò).

Se nessuno dei figli è terminato, la wait() ha un comportamento bloccante; esistono invece altre syscall che prevedono semantiche non bloccanti. In particolare, la syscall waitpid() permette di specificare di attendere la terminazione un determinato processo, ed inoltre accetta in input un flag che specifica un comportamento non bloccante. Altre due syscall, wait3() e wait4(), derivanti dai sistemi BSD, sono sostanzialmente analoghe, cambiando leggermente la sintassi. Si raccomanda di riferirsi alle manpage per avere informazioni su sintassi e semantica di waitpid(), wait3() e wait4().


next up previous contents index
Next: Caricamento di un programma Up: Processi Previous: Esercizio   Indice   Indice analitico
Giuseppe Lipari 2002-10-27