Creazione e terminazione dei
processi
Tommaso Motta
www.webalice.it/motta.tommaso
T. Motta
Generazione e terminazione processi
1
Introduzione

Sistema multitasking: più processi in esecuzione in
contemporanea


ho parallelismo reale solo se c’è un processore per ogni
processo, altrimenti i processi avanzano alternati (timesharing)
2 tipologie di processi


T. Motta
processi di sistema operativo: realizzano servizi e gestiscono
le risorse del sistema
processi utente: sono mandati in esecuzione dall’utente
Generazione e terminazione processi
2
Processi permanenti e temporanei

I processi possono essere:


permanenti: vengono creati all’avvio del sistema
operativo e continuano fino alla chiusura del s.o.
temporanei: vengono creati quando servono e poi
terminano

T. Motta
necessitano di meccanismi per la generazione e la
terminazione dei processi
Generazione e terminazione processi
3
Generazione dei processi

I processi temporanei possono essere generati da




altri processi (permanenti o temporanei)
o dalla richiesta di un nuovo processo da parte di un utente
interattivo (ad. es.: attivazione di un’icona)
Ogni creazione di un processo corrisponde ad una chiamata
di sistema (system call)
Quando un processo richiede la generazione di un processo
(processo figlio) deve indicare il programma (codice) da
associare al processo che viene generato
T. Motta
Generazione e terminazione processi
4
Generazione dei processi

Dopo la generazione del processo il padre può:

sospendersi in attesa che il figlio termini... oppure...

...continuare ad evolversi in concorrenza con il figlio

T. Motta
Un processo può suddividersi in un numero n di attività che
avanzano parallelamente
Generazione e terminazione processi
5
Attività per la generazione di un
processo

Per generare un processo il S.O. deve:

verificare la disponibilità di spazio in memoria RAM per
il processo e per il suo PCB

se non è disponibile la memoria bisogna fare swapping
(memoria virtuale)

assegnare la memoria al processo

creare il PCB
T. Motta
Generazione e terminazione processi
6
Terminazione di processi

I processi temporanei possono


T. Motta
terminare spontaneamente (normale conclusione o
condizioni di errori)
terminare involontariamente (errori “fatali” o fatti
terminare da altri processi o da un utente)
Generazione e terminazione processi
7
Terminazione dei processi

In un sistema sono necessari


meccanismi di terminazione utilizzabili dal processo che
intende terminare
meccanismi di soppressione con il quale un processo può
causare la terminazione di un altro processo temporaneo

i meccanismi di soppressione possono essere invocati solo
da:


T. Motta
processi antenati (padre) o processi permanenti
utente che ha mandato in esecuzione il processo o
amministratore
Generazione e terminazione processi
8
Terminazione dei processi


Quando un processo termina invia al processo
padre un segnale
Alla terminazione o soppressione di un processo è
necessario:



T. Motta
verificare la legittimità dell’operazione
(l’utente/processo può sopprimere questo processo?)
rilasciare la memoria e tutte le risorse del processo
notificare la terminazione al processo padre (se non è
già terminato prima...)
Generazione e terminazione processi
9
Windows: API per generazione e
terminazione di processi

Windows NON ha il concetto di gerarchia di processi

API utili per creare e terminare i processi:

CreateProcess(): crea un processo

CreateThread(): crea un thread in un processo esistente

ExitThread(): termina il thread corrente

ExitProcess(): termina il processo e tutti i suoi threa

T. Motta
TerminateProcess(): permette a un processo di far
terminare un altro processo
Generazione e terminazione processi
10
Creazione e terminazione
processi in Linux
Tommaso Motta
www.webalice.it/motta.tommaso
T. Motta
Generazione e terminazione processi
11
Gerarchia di processi

Ogni processo deriva dalla duplicazione di un processo
esistente



l’unico processo che non deriva da duplicazione è il processo
iniziale (init)
Un processo permanente o temporaneo può generare
processi figli temporanei
Tutti i processi sono legati in una struttura ad ALBERO

T. Motta
Il comando pstree mostra i processi eidenziando la struttura
gerarchica
Generazione e terminazione processi
12
Gerarchia di processi
T. Motta
Generazione e terminazione processi
13
Creazione di processi: fork


Il comando fork indica che in quel punto deve
essere attivato un nuovo processo
I due processi evolvono indipendentemente


l’esecuzione viene suddivisa in due esecuzioni distinte
Il comando crea un processo figlio che è la COPIA
ESATTA del processo padre

al padre viene restituito il PID del figlio (valore negativo
se non ha funzionato)

al figlio viene restituito il valore 0
T. Motta
Generazione e terminazione processi
14
Fork ( )



I due processi hanno descrittori (PCB) e immagini
distinte
Il processo figlio eredita da padre il programma e
l’immagine nel processore
Dopo la generazione i due processi avanzano
indipendentemente eseguendo lo stesso
programma
T. Motta
Generazione e terminazione processi
15
Fork e S.O.

Quando si usa la fork il S.O. deve:

allocare un nuovo PCB e inserirlo nella tabella dei processi

assegnare al processo un PID

fare una copia logica di tutti i dati del processo padre

in realtà molte aree di memoria rimangono condivise, vengono
duplicate solo le aree su cui uno dei due fa una modifica

restituire il PID del figlio al padre e 0 al figlio

collocare il nuovo processo nella lista dei processi pronti
T. Motta
Generazione e terminazione processi
16
Creazione: fork()
pid_t fork(void);


crea un nuovo processo con indice pid
lo spazio di indirizzamento del nuovo processo è un
duplicato di quello del padre

restituisce 0 al figlio e pid al padre

oppure -1 (solo al padre) in caso di fallimento

T. Motta
es. la tabella dei processi non ha più spazio ...
Generazione e terminazione processi
17
Terminazione dei processi

Un processo termina eseguendo la chiamata di
sistema exit che



libera tutte le risorse
“ripudia” i figli => diventano di proprietà di init e quando
muoiono vengono da lui eliminati
Il processo che esegue la exit diventa uno zombie


i processi genitori devono eliminare gli zombie
un processo può sopprimere un altro processo con la
chiamata di sitema kill
T. Motta
Generazione e terminazione processi
18
Terminazione: exit()
void exit(int status);

il codice di terminazione della exit (cioè l’intero passato
come parametro) viene “restituito" al padre.

Se il processo che termina non ha più un processo padre (è già
terminato) il valore viene restituito all’interprete comandi del
S.O.

chiude tutti i descrittori di file,

libera lo spazio di indirizzamento,

invia un segnale SIGCHLD al padre

T. Motta
se il processo padre è terminato, il processo ‘orfano’ viene
adottato da init (cioè il ppid viene settato a 1)
Generazione e terminazione processi
19
Esempio creazione di processi
/* frammento che crea un nuovo processo */
int pid;
/* pid del processo creato */
pid = fork();
if ( pid == 0 )
{ /* siamo nel figlio */
printf(“Processo figlio”);
exit(1);
}
else
{ /* siamo nel padre */
printf(“Processo padre”);
exit(1);
}
T. Motta
Generazione e terminazione processi
20
PID del processo: getpid()

La funzione getpid


consente ad un processo di conoscere il valore del
proprio pid
Prototipo getpid:
pid_t getpid(void)
T. Motta

il kernel ha pid 0

init ha pid 1
Generazione e terminazione processi
21
PID del padre: getppid()

La funzione getppid


consente ad un processo di conoscere il valore del pid
del processo padre
Prototipo getppid:
pid_t getppid(void)
T. Motta
Generazione e terminazione processi
22
Esempio 1
#include <stdio.h>
#include <sys/types.h>
void main(int argc, char * argv[])
{ pid_t pid;
int retstatus=0;
pid = fork();
if (pid==0) /* sono nel figlio*/
{printf (“sono il processo figlio\n”);
retstatus=1;
exit(retstatus);}
else /* pid != 0, sono nel padre */
{printf (“sono il processo padre\n”);
exit(retstatus);}
}
T. Motta
Generazione e terminazione processi
23
Esempio 2: getpid
#include <stdio.h>
#include <sys/types.h>
void main()
{ pid_t pid;
printf (“Prima della fork: PID = %d\n”, getpid());
pid = fork();
if (pid==0) /* PROCESSO FIGLIO*/
{printf (“FIGLIO: PID = %d\n”, getpid());
exit(0);}
else /* PROCESSO PADRE */
{printf (“PADRE: PID = %d\n”, getpid());
printf (“PADRE: PID DEL FIGLIO = %d\n”, pid);
exit(0);}
}
T. Motta
Generazione e terminazione processi
24
Esempio 2: esecuzione getpid
Prima della fork: PID = 3375
FIGLIO: PID = 3399
PADRE: PID = 3375
PADRE: PID DEL FIGLIO = 3399


Dal risultato dell’esecuzione si deduce che l’ordine di esecuzione
dei processi è stato: figlio e padre
Nota bene:
quando la fork è stata eseguita, è stato creato il secondo
processo e l’esecuzione può proseguire o con il processo padre
per primo oppure con il processo figlio per primo
T. Motta
Generazione e terminazione processi
25
Esempio 3: generazione di 2 figli
void main()
{ pid_t pid1, pid2;
pid1 = fork();
if (pid1==0) /* PRIMO PROCESSO FIGLIO*/
{printf (“FIGLIO 1: PID = %d\n”, getpid());
printf (“FIGLIO 1: eseguo exit\n”);
exit(0);}
else /* PROCESSO PADRE */
{pid2 = fork();
if (pid2==0) /* SECONDO PROCESSO FIGLIO*/
{printf (“FIGLIO 2: PID = %d\n”, getpid());
printf (“FIGLIO 2: eseguo exit\n”);
exit(0);}
else /* PROCESSO PADRE */
{printf (“PADRE: PID = %d\n”, getpid());
printf (“PADRE: PID DEL FIGLIO 1 = %d\n”, pid1);
printf (“PADRE: PID DEL FIGLIO 2 = %d\n”, pid2);
exit(0); }
}
T. Motta
Generazione e terminazione processi
26
Esempio 3: esecuzione

Nell’ipotesi che l’ordine di esecuzione sia

figlio1, padre, figlio2, padre
FIGLIO 1: PID = 4300
FIGLIO 1: eseguo exit
FIGLIO 2: PID = 4335
FIGLIO 2: eseguo exit
PADRE: PID = 3375
PADRE: PID DEL FIGLIO 1 = 4300
PADRE: PID DEL FIGLIO 2 = 4335
T. Motta
Generazione e terminazione processi
27
Esempio 4: ancora 2 figli...
void main()
{ pid_t pid;
pid = fork();
if (pid==0) /* PRIMO PROCESSO FIGLIO*/
{printf (“(1)sono il primo figlio con pid: = %d\n”,getpid());
exit(0);}
else /* PROCESSO PADRE */
{printf (“(2)sono il processo padre\n”);
printf (“(3)ho creato un primo figlio con pid: = %d\n”,pid);
printf (“(4)il mio pid e’: = %d\n”,getpid());
pid = fork();
if (pid==0) /* SECONDO PROCESSO FIGLIO*/
{printf (“(5)sono il secondo figlio con pid: = %d\n”,getpid());
exit(0);}
else /* PROCESSO PADRE */
{printf (“(6)sono il processo padre\n”);
printf (“(7)ho creato un secondo figlio con pid: =%d\n”,pid);
exit(0);}
}
T. Motta
}
Generazione e terminazione processi
28
Esempio 4: esecuzione
2)sono il processo padre
1)sono il primo figlio con pid: = 695
3)ho creato un primo figlio con pid: = 695
4)il mio pid e’: = 694
6)sono il processo padre
5)sono il secondo figlio con pid: = 696
7)ho creato un secondo figlio con pid: 696
T. Motta
Generazione e terminazione processi
29
Attesa di terminazione del figlio

Il processo padre, dopo aver generato il figlio può
sospendersi in attesa della sua terminazione:



invoca la chiamata di sistema wait che sincronizza il
padre con l’evento relativo alla terminazione del figlio
La wait permette di riunificare due o più processi
concorrenti in un unico processo
Il processo che chiama la wait rimane bloccato
fino a quando non è terminato il processo figlio
T. Motta
Generazione e terminazione processi
30
Attesa terminazione figlio: wait

La funzione wait



sospende l’esecuzione del processo padre che la esegue ed attende la
terminazione di un qualsiasi processo figlio;
se il figlio termina prima che il padre esegua la wait, l’esecuzione
della wait nel padre termina istantaneamente.
Prototipo wait:
pid_t wait (int*)


T. Motta
il valore restituito dalla funzione (di tipo pid_t) è il valore del pid del
figlio terminato.
il parametro passato per indirizzo assume il valore del codice di
terminazione del figlio (e cioè il valore del parametro della exit
eseguita dal figlio per terminare).
Generazione e terminazione processi
31
Esempio: wait
#include . . . .
void main(int argc, char * argv[])
{ pid_t pid;
int stato_exit, stato_wait;
pid = fork();
if (pid==0)
{printf (“sono il processo figlio\n”);
printf(“il mio pid e’: %d \n”,getpid( ));
stato_exit=5;
exit(stato_exit);}
else
{printf("Ho generato il processo figlio con pid %d\n",pid)
pid = wait(&stato_wait);
printf("E’ terminato il processo %d con esito %d\n",pid,
stato_wait/256);}
}
T. Motta
Generazione e terminazione processi
32
Attesa terminazione figlio: waitpid

La funzione waitpid



Sospende l’esecuzione del processo padre ed attende la terminazione
del processo figlio di cui viene fornito il pid;
se il figlio termina prima che il padre esegua la waitpid, l’esecuzione
della waitpid nel padre termina istantaneamente.
Prototipo waitpid
pid_t waitpid(pid_t pid, int *status, int options);

T. Motta
nel padre:

il valore resitituito assume il valore del pid del figlio terminato;

status assume il valore del codice di terminazione del processo figlio;

options specifica ulteriori opzioni (ipotizziamo > 0).
Generazione e terminazione processi
33
Esempio: waitpid
#include . . .
void main(int argc, char * argv[])
{ pid_t pid, my_pid;
int status;
pid = fork();
if (pid==0)
{/* CODICE DEL FIGLIO */ }
else /* pid != 0, sono nel padre */
{printf ("Ho generato il processo figlio con pid
%d\n",pid);
printf("Attendo la terminazione del figlio con pid
%d\n",pid);
my_pid = waitpid(pid, &status, 1);
printf("E’ terminato il processo %d con esito %d\n",my_pid,
status);}
T.
} Motta
Generazione e terminazione processi
34
Sostituzione del programma in
esecuzione: exec

La funzione exec

sostituisce il segmento codice e il segmento dati del
processo corrente con il codice e i dati di un programma
contenuto in un file eseguibile specificato.



Il segmento di sistema non viene sostituito (file e socket
rimangono aperti e disponibili)
il processo rimane lo stesso e quindi mantiene lo stesso pid
la funzione exec passa dei parametri al programma che
viene eseguito, tramite il meccanismo di passaggio dei
parametri al main argc e argv
T. Motta
Generazione e terminazione processi
35
Sintassi exec

Sintassi:
int execl(char *path_programma, char *arg0, char *arg1,..char
*argn);




path_programma: path completo del file eseguibile del nuovo programma da
lanciare
arg0,arg1, … argn: puntatori a stringhe che verranno passate come parametri al
main del nuovo programma

arg0 deve essere il nome del programma

argn in chiamata deve essere il valore NULL
il valore restituito è:

0 se l’operazione è stata eseguita correttamente;

-1 se c’è stato un errore e l’operazione di sostituzione del codice è fallita.
Al momento dell’esecuzione del main del nuovo programma - void main (int
argc, char *argv[]) - arg0, arg1 .. vengono resi accessibili tramite l’array
di puntatori argv
T. Motta
Generazione e terminazione processi
36
Esempio: exec
/* programma main1 */
/* programma exec1 */
#include <stdio.h>
#include <stdio.h>
void main(int argc, char * argv[])
#include <sys/types.h>
{int i;
void main(int argc, char * argv[])
printf (“programma main1 in esecuzione\n”);
{char PO[]=“main1”;
printf (“ho ricevuto %d parametri\n”, argc);
char P1[]=“parametro1”;
for (i=0; i<argc; i++)
char P2[]=“parametro2”;
printf(“il parametro %d e’:
printf (“programma exec1 in esecuzione\n”);
%s \n”,argv[i]);
execl(“/antola/esempi/main1”,P0,P1,P2,NULL);
}
printf (“errore di exec”);
}
T. Motta
Generazione e terminazione processi
37
Esempio: esecuzione
Eseguo il programma exec1:
programma exec1 in esecuzione
programma main1 in esecuzione
ho ricevuto 3 parametri
il parametro 0 e’:main1
il parametro 1 e’:parametro1
il parametro 2 e’:parametro2
T. Motta
Generazione e terminazione processi
38
Utilizzo fork-exec

La sostituzione di codice non implica necessariamente la
generazione di un figlio


in questo caso, quando il programma che è stato lanciato in
esecuzione tramite la execl termina, termina anche il
processo che lo ha lanciato (sono lo stesso processo!!)
E’ necessario creare un nuovo processo, che effettua la
sostituzione di codice (utilizzo di fork- exec), quando è
necessario “mantenere in vita” il processo di partenza,
dopo l’esecuzione del codice sostituito

T. Motta
spesso questo implica che il padre attenda la terminazione del
programma lanciato con mutazione di codice
Generazione e terminazione processi
39
Esempio: fork-exec
void main()
{ pid_t pid, chpid;
pid = fork();
if (pid==0)
/* PROCESSO FIGLIO*/
{printf (“FIGLIO: prima del cambio di codiced\n”)
printf (“FIGLIO: PID = %d\n”, getpid());
execl(“./prog”, “prog”, NULL);
printf (“FIGLIO: errore nel cambio di codice\n”);
exit(1);}
else
/* PROCESSO PADRE */
{printf (“PADRE: wait\n”);
chpid = wait (NULL);
printf (“PADRE: PID DEL FIGLIO = %d\n”, chpid);
exit(0); }
T. Motta
}
Generazione e terminazione processi
40
Esempio: fork-exec (...continuo)
/* Programma prog*/
void main (int argc, char * argv[])
{
printf (“PROG: PID = %d\n”, getpid());
printf (“PROG: exit\n”);
}

ESECUZIONE nell’ipotesi che venga eseguito prima il padre e poi il figlio
PADRE: wait
FIGLIO: prima del cambio del codice
FIGLIO: PID = 4995
PROG: PID = 4995
PROG: exit
PADRE:
T. Motta
PID DEL FIGLIO =Generazione
4995 e terminazione processi
41
Scarica

Creazione e terminazione dei processi su Linux