Un processo è, essenzialmente, un programma in esecuzione.
Ad ogni processo vengono associati:
Ad ogni processo è associato un identificativo numerico, chiamato PID.
Per visualizzare il PID della propria shell Bash, si può impartire il comando ps:
$ ps
PID TTY TIME CMD
18945 pts/3 00:00:00 bash
19019 pts/3 00:00:00 ps
... oppure sfruttare la variabile $$:
$ echo $$
18945
Nei sistemi Un*x, quando un processo ne crea un altro, "padre" e "figlio" rimangono in qualche modo associati. Per ogni processo, infatti, è noto qual è il processo padre (detto PPID, Parent PID).
Il rapporto gerarchico può essere osservato lanciando una nuova shell dalla shell corrente:
$ bash
$ ps
PID TTY TIME CMD
18945 pts/3 00:00:00 bash
19058 pts/3 00:00:00 bash
19074 pts/3 00:00:00 ps
$ ps --ppid 18945 # elenca i processi che hanno come padre il processo 18945
PID TTY TIME CMD
19058 pts/3 00:00:00 bash
La creazione di un nuovo processo da parte del processo padre viene effettuata con la chiamata di sistema fork.
Vediamo un semplice esempio in C.
#include <stdio.h>
int main(int argc, char **argv)
{
int child_pid = fork();
if (child_pid == -1) {
printf("fork() fallita\n");
return 1;
}
else if (child_pid) {
printf("Sono il padre, il PID di mio figlio è %d.\n", child_pid);
}
else {
printf("Sono il figlio.\n");
}
}
Spesso il processo figlio ha bisogno di un codice eseguibile diverso da quello del processo padre. Eseguirà allora una chiamata di sistema dela famiglia exec, con la quale il sistema sostituirà l'intera immagine di memoria con il file nominato nel suo primo parametro.
Un semplice esempio:
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
int child_pid = fork();
if (child_pid) {
printf("Sono il padre, il PID di mio figlio è %d.\n", child_pid);
}
else {
printf("Dovrei eseguire cal\n");
static char *arguments[]={"cal"};
execve("/usr/bin/cal", arguments, envp);
printf("Questa istruzione non verrà eseguita\n");
}
}
Se un processo fa un fork e termina prima del processo figlio generato, il processo figlio viene "adottato" dal processo init (l'antenato comune di tutti i processi, che ha PID 1).
Lo schema è il seguente.
PPPPPPPPPPPPP
FFFFAAAAAAAAAAAAAAAAA
P = processo padre
F = processo figlio
A = processo figlio adottato da init quando il padre termina
Se un figlio termina il lavoro prima del processo padre, rimane nello stato c.d. zombie fino al termine di quest'ultimo.
Lo schema è il seguente.
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
FFFFFFFFZZZZZZZZZZZZZZZZZZZZZZZZZ
P = processo padre
F = processo figlio
Z = processo figlio che diventa zombie al suo termine
Più correttamente, il processo padre dovrebbe porsi in attesa del processo figlio, con una chiamata di sistema waitpid.
Il caso, a seconda di chi tra padre e figlio finisce prima il proprio lavoro, potrebbe essere uno dei seguenti:
a)
PPPPPPPPPPPPPPPPWWWWWWWWWWWWWWWWWWWWWWWWWP
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
b)
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPWPPPPPPPPPPP
FFFFFFFZZZZZZZZZZZZZZZZZZZZZZZ
P = processo padre
F = processo figlio
W = processo padre in attesa
La gerarchia dei processi può essere visualizzata con il comando pstree.
$ pstree
init---NetworkManager---{NetworkManager}
+-firefox---run-mozilla.sh---firefox-bin---10*[{firefox-bin}]
+-gdm---gdm-+-Xorg---Xorg
+-5*[getty]
+-gnome-terminal-+-bash---ssh
| +-bash
| +-bash---cat
| +-bash---pstree
| +-{gnome-terminal}
+-quanta
+-wpa_supplicant
(output ridotto)
Con il comando pstree -p si può visualizzare il PID di ogni processo.
I sistemi Linux mettono a disposizione una speciale directory, denominata /proc, contenente informazioni, in forma di file, sui processi.
Per ogni processo, nella directory /proc/PID, si hanno ad esempio:
Si veda proc(5) per ulteriori informazioni.
Il programma ps è lo strumento principale di visualizzazione delle informazioni relative ai processi.
Il comando ps funziona con opzioni espresse in tre forme diverse:
Le opzioni hanno significati diversi in Unix98 e BSD. Ad esempio:
$ ps a
PID TTY STAT TIME COMMAND
4449 tty4 Ss+ 0:00 /sbin/getty 38400 tty4
...
5570 tty7 SL+ 0:00 /usr/bin/X :0 -br -audit 0 -auth /var/lib/gdm/:0.Xaut
5825 pts/0 Ss+ 0:00 bash
6611 pts/1 Ss 0:00 bash
7328 pts/1 R+ 0:00 ps a
$ ps -a
PID TTY TIME CMD
5570 tty7 00:00:00 Xorg
7329 pts/1 00:00:00 ps
Alcune opzioni frequentemente utilizzate sono:
a: mostra tutti i processi di tutti gli utentiu: usa un formato di visualizzazione orientato all'utentex: mostra anche i processi senza un terminaleNotare la quasi completa equivalenza di ps aux e ps -ef.
Un'intera pipeline può essere eseguita in background posponendo un ampersand alla fine del comando.
Un lavoro (job) in background può essere riportato in foreground con il comando fg.
Il lavoro in foreground può essere sospeso premendo ctrl-Z (^Z).
$ yes > /dev/null &
[1] 7489
$ fg %1
yes > /dev/null
(ctrl-Z)
[1]+ Stopped yes > /dev/null
$ bg %1
[1]+ yes > /dev/null &
Un processo può trovarsi in uno dei seguenti stati:
D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being
traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct ("zombie") process, terminated but not reaped by its
parent.
(da ps(1))
Un meccanismo fondamentale nella comunicazione tra processi consiste nell'invio di segnali. I segnali possono essere inviati:
killstty -a)Per inviare il segnale SIGHUP al processo 9876 si può digitare:
kill -SIGHUP 9876
kill -HUP 9876
kill -1 9876
L'elenco completo dei segnali inviabili può essere visualizzato con il comando kill -l. I segnali più importanti sono:
Alcuni programmi che possono essere utili:
pgrep, per trovare un processo in base a determinati criteripkill, per inviare un segnale ai processi individuati in base a determinati criterikillall, per inviare un segnale a tutti i processi di un determinato programmanohup, per avviare un programma in modo che non termini quando viene chiuso il terminale da cui è stato lanciatolsof -p, per avere un elenco dei file utilizzati da un determinato processoAd ogni processo è associato un livello di priorità.
-20 (alta) 0 (normale) 19 (bassa)
+------------------------+--------------------------+
I programmi possono essere avviati con bassa priorità (da tutti) o con alta priorità (da root) tramite il comando nice
Ai processi può essere cambiata la priorità con il comando renice.
Per una gestione interattiva dei processi, può essere utile il programma top.
Alcune opzioni interessanti possono essere attivate con la pressione di:
[spazio], per aggiornare il displayh, per ottenere aiutok, per inviare un segnale ad un processoi, per mostrare/nascondere i processi in stato Sleep/Zombien, per indicare quanti processi mostrarer, per cambiare la priorità di un processops, aiutandosi con la guida in linea.jobs per visualizzare l'elenco dei lavori in esecuzione in background.ps gli stati Running, Interruptible sleep, Stopped, Defunct (zombie) di processi appositamente creati.ddbc per calcolare le prime 2000 cifre di Pi Greco, misurando il tempo impiegato con time, prima in maniera normale e poi con bassa priorità