Un processus n'est rien d'autre qu'une instance en cours d'exécution d'un programme. Il se définit également comme un programme en action.
Le concept de processus est le concept fondamental d'un système Linux. Les processus peuvent générer d'autres processus, tuer d'autres processus, communiquer avec d'autres processus et bien plus encore.
Dans ce didacticiel, nous discuterons du cycle de vie d'un processus et aborderons divers aspects qu'un processus traverse au cours de son cycle de vie.
1. Code Vs Programme Vs Processus
Commençons par comprendre la différence entre code, programme et processus.
Code : Voici un exemple de code :
#include <stdio.h> #include <unistd.h> int main(void) { printf("\n Hello World\n"); sleep(10); return 0; }
Enregistrons le morceau de code ci-dessus dans un fichier nommé helloWorld.c. Donc ce fichier devient du code.
Programme : Maintenant, lorsque le code est compilé, il produit un fichier exécutable. Voici comment le code ci-dessus est compilé :
$ gcc -Wall helloWorld.c -o helloWorld
Cela produirait un exécutable nommé helloWorld. Cet exécutable est appelé programme.
Processus : Maintenant, lançons cet exécutable :
$ ./helloWorld Hello World
Une fois exécuté, un processus correspondant à cet exécutable (ou programme) est créé. Ce processus exécutera tout le code machine qui était là dans le programme. C'est la raison pour laquelle un processus est appelé instance en cours d'exécution d'un programme.
Pour vérifier les détails du processus nouvellement créé, exécutez la commande ps de la manière suivante :
$ ps -aef | grep hello* 1000 6163 3017 0 18:15 pts/0 00:00:00 ./helloWorld
Pour comprendre la sortie de la commande ps, lisez notre article sur les exemples de commande 7 ps.
2. Processus parent et enfant
Chaque processus a un processus parent et il peut avoir ou non des processus enfants. Prenons cela un par un. Considérez la sortie de la commande ps sur ma machine 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
Les nombres entiers dans les deuxième et troisième colonnes de la sortie ci-dessus représentent l'ID de processus et l'ID de processus parent. Observez les chiffres soulignés en gras. Lorsque j'ai exécuté la commande 'ps -aef', un processus a été créé, son ID de processus est 6191. Maintenant, regardez son ID de processus parent, c'est 3079. Si vous regardez vers le début de la sortie, vous verrez cet ID 3079 est l'ID de processus du processus bash. Cela confirme que le shell bash est le parent de toute commande que vous exécutez.
De même, même pour les processus qui ne sont pas créés via le shell, il existe un processus parent. Exécutez simplement la commande 'ps -aef' sur votre machine Linux et observez la colonne PPID (ID de processus parent). Vous ne verrez aucune entrée vide dedans. Cela confirme que chaque processus a un processus parent.
Venons-en maintenant aux processus enfants. Chaque fois qu'un processus crée un autre processus, le premier est appelé parent tandis que le second est appelé processus enfant. Techniquement, un processus enfant est créé en appelant la fonction fork() depuis le code. Habituellement, lorsque vous exécutez une commande à partir du shell, fork() est suivi d'une série de fonctions exec().
Nous avons discuté du fait que chaque processus a un processus parent, cela peut amener une question :qu'adviendra-t-il d'un processus enfant dont le processus parent est tué ? Eh bien, c'est une bonne question, mais revenons-y plus tard.
3. Le processus d'initialisation
Lorsque le système Linux est démarré, la première chose qui est chargée en mémoire est vmlinuz. C'est l'exécutable du noyau Linux compressé. Cela se traduit par la création du processus init. C'est le premier processus créé. Le processus d'initialisation a un PID de un et est le super parent de tous les processus d'une session Linux. Si vous considérez la structure des processus Linux comme un arbre, alors init est le nœud de départ de cet arbre.
Pour confirmer que init est le premier processus, vous pouvez exécuter la commande pstree sur votre machine Linux. Cette commande affiche l'arborescence des processus pour une session Linux.
Voici un exemple de sortie :
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}] ... ... ...
La sortie confirme que init est en haut de l'arborescence des processus. De plus, si vous observez le texte en gras, vous verrez la relation parent-enfant complète du processus pstree. En savoir plus sur pstree dans notre article sur tree et pstree.
Maintenant, revenons à la question (que nous avons laissée ouverte dans la dernière section) sur les conséquences lorsque le processus parent est tué alors que l'enfant est toujours en vie. Et bien dans ce cas, l'enfant devient évidemment orphelin mais est adopté par le processus init. Ainsi, le processus init devient le nouveau parent des processus enfants dont les parents sont terminés.
4. Cycle de vie du processus
Dans cette section, nous discuterons du cycle de vie d'un processus Linux normal avant qu'il ne soit tué et supprimé de la table des processus du noyau.
- Comme déjà discuté, un nouveau processus est créé via fork() et si un nouvel exécutable doit être exécuté, la famille de fonctions exec() est appelée après fork(). Dès que ce nouveau processus est créé, il est mis en file d'attente dans la file d'attente des processus prêts à être exécutés.
- Si seul fork() a été appelé, il est fort probable que le nouveau processus s'exécute en mode utilisateur, mais si exec() est appelé, le nouveau processus s'exécutera en mode noyau jusqu'à ce qu'un nouvel espace d'adressage de processus soit créé pour lui.
- Pendant que le processus est en cours d'exécution, un processus de priorité plus élevée peut le préempter via une interruption. Dans ce cas, le processus préempté passe à nouveau dans la file d'attente des processus prêts à s'exécuter. Ce processus est repris par le planificateur à un stade ultérieur.
- Un processus peut entrer en mode noyau pendant son exécution. Cela est possible lorsqu'il faut accéder à certaines ressources comme un fichier texte qui est conservé sur le disque dur. Comme les opérations impliquant l'accès au matériel peuvent prendre du temps, il est fort probable que le processus s'endorme et ne se réveille que lorsque les données demandées sont disponibles. Lorsque le processus est réveillé, cela ne signifie pas qu'il commencera à s'exécuter immédiatement, il sera à nouveau mis en file d'attente et sera sélectionné pour exécution par le planificateur au moment approprié.
- Un processus peut être tué de plusieurs façons. Il peut appeler la fonction exit() pour quitter ou traiter les signaux Linux pour quitter. De plus, certains signaux ne peuvent pas être détectés et entraînent l'arrêt immédiat du processus.
- Il existe différents types de processus Linux. Une fois le processus tué, il n'est pas complètement éliminé. Une entrée contenant des informations la concernant est conservée dans la table d'adresses du processus du noyau jusqu'à ce que le processus parent appelle explicitement les fonctions wait() ou waitpid() pour obtenir l'état de sortie du processus enfant. Jusqu'à ce que le processus parent le fasse, le processus terminé est appelé processus zombie.