GNU/Linux >> Linux Esercitazione >  >> Linux

Come funziona il ciclo di vita dei processi Linux:processo padre, figlio e inizializzazione

Un processo non è altro che un'istanza in esecuzione di un programma. È anche definito come un programma in azione.

Il concetto di processo è il concetto fondamentale di un sistema Linux. I processi possono generare altri processi, uccidere altri processi, comunicare con altri processi e molto altro.

In questo tutorial, discuteremo del ciclo di vita di un processo e analizzeremo vari aspetti che un processo attraversa nel suo ciclo di vita.

1. Codice vs programma vs processo

Per prima cosa comprendiamo la differenza tra codice, programma e processo.

Codice: Di seguito è riportato un esempio di codice:

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    printf("\n Hello World\n");
    sleep(10);

    return 0;
}

Salviamo la parte di codice sopra in un file chiamato helloWorld.c. Quindi questo file diventa codice.

Programma: Ora, quando il codice viene compilato, produce un file eseguibile. Ecco come viene compilato il codice sopra:

$ gcc -Wall helloWorld.c -o helloWorld

Ciò produrrebbe un eseguibile chiamato helloWorld. Questo eseguibile è noto come programma.

Processo: Ora, eseguiamo questo eseguibile:

$ ./helloWorld 

 Hello World

Una volta eseguito, viene creato un processo corrispondente a questo eseguibile (o programma). Questo processo eseguirà tutto il codice macchina che era presente nel programma. Questo è il motivo per cui un processo è noto come istanza in esecuzione di un programma.

Per controllare i dettagli del processo appena creato, esegui il comando ps nel modo seguente:

$ ps -aef | grep hello*
1000      6163  3017  0 18:15 pts/0    00:00:00 ./helloWorld

Per comprendere l'output del comando ps, leggi il nostro articolo su 7 esempi di comandi ps.

2. Processo genitore e figlio

Ogni processo ha un processo padre e può avere o meno processi figlio. Prendiamo questo uno per uno. Considera l'output del comando ps sulla mia macchina Ubuntu:

1000      3008     1  0 12:50 ?        00:00:23 gnome-terminal
1000      3016  3008  0 12:50 ?        00:00:00 gnome-pty-helper
1000      3017  3008  0 12:50 pts/0    00:00:00 bash
1000      3079  3008  0 12:58 pts/1    00:00:00 bash
1000      3321     1  0 14:29 ?        00:00:12 gedit
root      5143     2  0 17:20 ?        00:00:04 [kworker/1:1]
root      5600     2  0 17:39 ?        00:00:00 [migration/1]
root      5642     2  0 17:39 ?        00:00:00 [kworker/u:69]
root      5643     2  0 17:39 ?        00:00:00 [kworker/u:70]
root      5677     2  0 17:39 ?        00:00:00 [kworker/0:2]
root      5680     2  0 17:39 ?        00:00:00 [hci0]
root      5956   916  0 17:39 ?        00:00:00 /sbin/dhclient -d -sf /usr/lib/NetworkManager/nm-dhcp-client.action -pf /run/sendsigs.
root      6181     2  0 18:35 ?        00:00:00 [kworker/1:0]
root      6190     2  0 18:40 ?        00:00:00 [kworker/1:2]
1000      6191  3079  0 18:43 pts/1    00:00:00 ps -aef

I numeri interi nella seconda e terza colonna dell'output sopra rappresentano l'ID processo e l'ID processo padre. Osservare le cifre evidenziate in grassetto. Quando ho eseguito il comando "ps -aef", è stato creato un processo, il suo ID processo è 6191. Ora, guarda l'ID del processo padre, è 3079. Se guardi verso l'inizio dell'output vedrai quell'ID 3079 è l'ID del processo bash. Questo conferma che bash shell è il genitore per qualsiasi comando che esegui attraverso di essa.

Allo stesso modo, anche per i processi che non vengono creati tramite la shell, esiste un processo padre. Basta eseguire il comando "ps -aef" sulla tua macchina Linux e osservare la colonna PPID (ID processo padre). Non vedrai alcuna voce vuota al suo interno. Ciò conferma che ogni processo ha un processo padre.

Ora, veniamo ai processi figlio. Ogni volta che un processo crea un altro processo, il primo è chiamato genitore mentre il secondo è chiamato processo figlio. Tecnicamente, un processo figlio viene creato chiamando la funzione fork() dall'interno del codice. Di solito quando si esegue un comando dalla shell, fork() è seguito dalla serie di funzioni exec().

Abbiamo discusso del fatto che ogni processo ha un processo genitore, questo può portare a una domanda che cosa accadrà a un processo figlio il cui processo genitore viene ucciso? Bene, questa è una buona domanda, ma torniamo sull'argomento qualche tempo dopo.

3. Il processo di inizializzazione

Quando il sistema Linux viene avviato, la prima cosa che viene caricata in memoria è vmlinuz. È l'eseguibile compresso del kernel Linux. Ciò si traduce nella creazione del processo init. Questo è il primo processo che viene creato. Il processo Init ha un PID pari a uno ed è il super genitore di tutti i processi in una sessione Linux. Se consideri la struttura del processo Linux come un albero, init è il nodo iniziale di quell'albero.

Per confermare che init è il primo processo, puoi eseguire il comando pstree sulla tua macchina Linux. Questo comando mostra l'albero dei processi per una sessione Linux.

Ecco un esempio di output:

init-+-NetworkManager-+-dhclient
     |                |-dnsmasq
     |                `-3*[{NetworkManager}]
     |-accounts-daemon---2*[{accounts-daemon}]
     |-acpid
     |-at-spi-bus-laun-+-dbus-daemon
     |                 `-3*[{at-spi-bus-laun}]
     |-at-spi2-registr---{at-spi2-registr}
     |-avahi-daemon---avahi-daemon
     |-bamfdaemon---3*[{bamfdaemon}]
     |-bluetoothd
     |-colord---{colord}
     |-console-kit-dae---64*[{console-kit-dae}]
     |-cron
     |-cups-browsed
     |-cupsd
     |-2*[dbus-daemon]
     |-dbus-launch
     |-dconf-service---2*[{dconf-service}]
     |-evince---3*[{evince}]
     |-evinced---{evinced}
     |-evolution-sourc---2*[{evolution-sourc}]
     |-firefox-+-plugin-containe---16*[{plugin-containe}]
     |         `-36*[{firefox}]
     |-gconfd-2
     |-gedit---3*[{gedit}]
     |-6*[getty]
     |-gnome-keyring-d---7*[{gnome-keyring-d}]
     |-gnome-terminal-+-bash
     |                |-bash-+-less
     |                |      `-pstree
     |                |-gnome-pty-helpe
     |                `-3*[{gnome-terminal}]
     |-gvfs-afc-volume---2*[{gvfs-afc-volume}]
     |-gvfs-gphoto2-vo---{gvfs-gphoto2-vo}
     |-gvfs-mtp-volume---{gvfs-mtp-volume}
     |-gvfs-udisks2-vo---{gvfs-udisks2-vo}
     |-gvfsd---{gvfsd}
     |-gvfsd-burn---2*[{gvfsd-burn}]
     |-gvfsd-fuse---4*[{gvfsd-fuse}]
     ...
     ...
     ...

L'output conferma che init è in cima all'albero dei processi. Inoltre, se osservi il testo in grassetto, vedrai la relazione genitore-figlio completa del processo pstree. Leggi di più su pstree nel nostro articolo su tree e pstree.

Ora, torniamo alla domanda (lasciata aperta nell'ultima sezione) sulle conseguenze quando il processo genitore viene ucciso mentre il bambino è ancora vivo. Ebbene in questo caso, il bambino diventa ovviamente orfano ma viene adottato dal processo init. Quindi, init process diventa il nuovo genitore di quei processi figlio i cui genitori sono terminati.

4. Ciclo di vita del processo

In questa sezione, discuteremo il ciclo di vita delle normali coperture di un processo Linux prima che venga terminato e rimosso dalla tabella dei processi del kernel.

  • Come già discusso, un nuovo processo viene creato tramite fork() e se deve essere eseguito un nuovo eseguibile, la famiglia di funzioni exec() viene chiamata dopo fork(). Non appena questo nuovo processo viene creato, viene messo in coda nella coda dei processi pronti per l'esecuzione.
  • Se è stato chiamato solo fork(), è molto probabile che il nuovo processo venga eseguito in modalità utente, ma se viene chiamato exec(), il nuovo processo verrà eseguito in modalità kernel finché non verrà creato un nuovo spazio di indirizzi del processo.
  • Mentre il processo è in esecuzione, un processo con priorità più alta può anticiparlo tramite un'interruzione. In questo caso, il processo annullato va nuovamente nella coda dei processi pronti per l'esecuzione. Questo processo viene ripreso dallo scheduler in una fase successiva.
  • Un processo può entrare in modalità kernel durante l'esecuzione. Questo è possibile quando è necessario accedere ad alcune risorse come file di testo che sono conservati sul disco rigido. Poiché le operazioni che coinvolgono l'accesso all'hardware possono richiedere tempo, è molto probabile che il processo vada in modalità di sospensione e si riattivi solo quando i dati richiesti sono disponibili. Quando il processo viene attivato, non significa che inizierà immediatamente l'esecuzione, si accoderà nuovamente e verrà prelevato per l'esecuzione dallo scheduler al momento opportuno.
  • Un processo può essere interrotto in molti modi. Può chiamare la funzione exit() per uscire o elaborare segnali Linux per uscire. Inoltre, alcuni segnali non possono essere rilevati e provocano l'interruzione immediata del processo.
  • Esistono diversi tipi di processi Linux. Una volta terminato, il processo non viene completamente eliminato. Una voce contenente alcune informazioni ad essa correlate viene conservata nella tabella degli indirizzi del processo del kernel fino a quando il processo padre non chiama esplicitamente le funzioni wait() o waitpid() per ottenere lo stato di uscita del processo figlio. Fino a quando il processo padre non esegue questa operazione, il processo terminato è noto come processo zombie.

Linux
  1. Come uccidere un processo zombie su Linux

  2. Come trovare e uccidere il processo Zombie in Linux

  3. Come installare vtop su Linux

  4. Come installare e configurare Monit su Linux per il monitoraggio dei processi

  5. Come far morire il processo figlio dopo che il genitore è uscito?

Come visualizzare i PPID in Linux

Come lavorare con il processo in primo piano e in background in Linux

Come KILL un processo su Linux

Come trovare il PID e il PPID di un processo in Linux

Come uccidere i processi in Linux usando kill, killall e pkill

Come tracciare e tracciare un processo Linux