Maison > Article > Opération et maintenance > Il existe plusieurs états de processus Linux
Le processus Linux a 6 états : 1. R état exécutable, seuls les processus dans cet état peuvent s'exécuter sur le CPU ; 2. S état de veille interrompue, le processus dans cet état attend qu'un certain événement se produise et est suspendu. ; 3. D état de veille ininterrompue, le processus est en état de veille, mais le processus est ininterrompu à ce moment ; 4. T état de pause ou état de suivi, envoie un signal SIGSTOP au processus, et il répondra au signal d'entrée dans le État T ; 5. État zombie Z, indiquant qu’un processus est sur le point de mourir ; 6. État de mort X ;
L'environnement d'exploitation de ce tutoriel : système linux7.3, ordinateur Dell G3.
Sous Linux, un processus comporte 6 états, à savoir : l'état exécutable, l'état de veille interruptionsable, l'état de veille ininterruptible, l'état suspendu ou état de suivi, l'état zombie et l'état mort.
Explication détaillée de l'état du processus Linux
R(TASK_RUNNING) état de l'exécutable
Seuls les processus dans cet état peuvent s'exécuter sur le CPU. Il peut y avoir plusieurs processus dans l'état exécutable en même temps, et les structures task_struct (blocs de contrôle de processus) de ces processus sont placées dans la file d'attente exécutable de la CPU correspondante (un processus ne peut apparaître que dans la file d'attente exécutable d'une CPU à la plupart). La tâche du planificateur de processus est de sélectionner un processus dans la file d'attente exécutable de chaque processeur à exécuter sur ce processeur.
De nombreux manuels de systèmes d'exploitation définissent les processus qui s'exécutent sur le processeur comme l'état RUNNING, et les processus qui sont exécutables mais dont l'exécution n'a pas encore été planifiée comme l'état READY. Ces deux états sont unifiés dans l'état TASK_RUNNING sous Linux.
S(TASK_INTERRUPTIBLE) État de veille interrompue
Le processus dans cet état est suspendu car il attend qu'un certain événement se produise (comme l'attente d'une connexion socket, l'attente d'un sémaphore). Les structures task_struct de ces processus sont mises dans la file d'attente des événements correspondants. Lorsque ces événements se produisent (déclenchés par des interruptions externes ou déclenchés par d'autres processus), un ou plusieurs processus dans la file d'attente correspondante seront réveillés.
Grâce à la commande ps, nous verrons que, dans des circonstances normales, la grande majorité des processus de la liste des processus sont dans l'état TASK_INTERRUPTIBLE (sauf si la charge sur la machine est très élevée). Après tout, il n'y a qu'un ou deux processeurs, et il y a souvent des dizaines, voire des centaines de processus. Si la plupart des processus ne sont pas en veille, comment le processeur peut-il réagir ?
D(TASK_UNINTERRUPTIBLE) État de veille ininterrompue
Semblable à l'état TASK_INTERRUPTIBLE, le processus est en état de veille, mais le processus est ininterrompu en ce moment. Ininterruptible ne signifie pas que le processeur ne répond pas aux interruptions du matériel externe, mais que le processus ne répond pas aux signaux asynchrones.
Dans la plupart des cas, un processus devrait toujours être capable de répondre aux signaux asynchrones lorsqu'il est en état de veille. Sinon, vous serez surpris de constater que kill -9 ne peut pas tuer un processus en veille ! On peut donc aussi facilement comprendre pourquoi les processus vus par la commande ps apparaissent rarement dans l'état TASK_UNINTERRUPTIBLE, mais toujours dans l'état TASK_INTERRUPTIBLE.
La signification de l'état TASK_UNINTERRUPTIBLE est que certains flux de traitement du noyau ne peuvent pas être interrompus. Si vous répondez à un signal asynchrone, un processus de traitement des signaux asynchrones sera inséré dans le flux d'exécution du programme (ce processus inséré ne peut exister qu'en mode noyau, ou peut s'étendre au mode utilisateur), donc le processus d'origine sera être interrompu.
Lorsque le processus fonctionne sur certains matériels (par exemple, le processus appelle l'appel système de lecture pour lire un certain fichier de périphérique, et l'appel système de lecture exécute finalement le code du pilote de périphérique correspondant et interagit avec le périphérique physique correspondant), Il peut être nécessaire d'utiliser l'état TASK_UNINTERRUPTIBLE pour protéger le processus afin d'éviter que l'interaction entre le processus et le périphérique ne soit interrompue et ne fasse tomber le périphérique dans un état incontrôlable. L'état TASK_UNINTERRUPTIBLE dans ce cas est toujours de très courte durée et fondamentalement impossible à capturer via la commande ps.
Il existe également un état TASK_UNINTERRUPTIBLE facile à capturer dans les systèmes Linux. Après avoir exécuté l'appel système vfork, le processus parent entrera dans l'état TASK_UNINTERRUPTIBLE jusqu'à ce que le processus enfant appelle exit ou exec.
T (TASK_STPPED ou TASK_TRACED) état de suspension ou état de trace
Envoyez un signal SIGSTOP au processus, et il entrera dans l'état TASK_STOPPED en réponse au signal (sauf si le processus lui-même est dans l'état TASK_UNINTERRUPTIBLE et ne le fait pas répondre au signal). (SIGSTOP, comme le signal SIGKILL, est très obligatoire. Le processus utilisateur n'est pas autorisé à réinitialiser la fonction de traitement du signal correspondante via l'appel système de la série de signaux.)
L'envoi d'un signal SIGCONT au processus peut le restaurer de l'état TASK_STOPPED à l'état TASK_RUNNING.
Lorsqu'un processus est tracé, il se trouve dans l'état spécial TASK_TRACED. « Être suivi » signifie que le processus est en pause et attend que le processus qui le suit agisse sur lui. Par exemple, si vous définissez un point d'arrêt sur le processus suivi dans gdb, le processus sera dans l'état TASK_TRACED lorsqu'il s'arrêtera au point d'arrêt. À d’autres moments, le processus suivi se trouve toujours dans les états mentionnés précédemment.
Pour le processus lui-même, les états TASK_STOPPED et TASK_TRACED sont très similaires, indiquant tous deux que le processus est suspendu.
L'état TASK_TRACED équivaut à une couche de protection supplémentaire au-dessus de TASK_STOPPED. Le processus dans l'état TASK_TRACED ne peut pas être réveillé en réponse au signal SIGCONT. Le processus débogué ne peut revenir à l'état TASK_RUNNING que jusqu'à ce que le processus de débogage exécute des opérations telles que PTRACE_CONT et PTRACE_DETACH via l'appel système ptrace (les opérations sont spécifiées via les paramètres de l'appel système ptrace) ou que le processus de débogage se termine.
Z(TASK_DEAD - EXIT_ZOMBIE) État zombie, le processus devient un processus zombie
Le processus est dans l'état TASK_DEAD pendant le processus de sortie.
Lors de ce processus de sortie, toutes les ressources occupées par le processus seront recyclées, à l'exception de la structure task_struct (et quelques ressources). Ainsi, le processus ne dispose que du shell vide de task_struct, c'est pourquoi on l'appelle un zombie.
La raison pour laquelle task_struct est conservée est que task_struct stocke le code de sortie du processus et certaines informations statistiques. Et son processus parent se souciera probablement de ces informations. Par exemple, dans le shell, la variable $? stocke le code de sortie du dernier processus de premier plan qui s'est terminé, et ce code de sortie est souvent utilisé comme condition de jugement de l'instruction if.
Bien sûr, le noyau peut également enregistrer ces informations ailleurs et libérer la structure task_struct pour économiser de l'espace. Cependant, il est plus pratique d'utiliser la structure task_struct, car la relation de recherche de pid à task_struct a été établie dans le noyau, ainsi que la relation parent-enfant entre les processus. Pour libérer task_struct, vous devez créer de nouvelles structures de données afin que le processus parent puisse trouver les informations de sortie de son processus enfant.
Le processus parent peut attendre la sortie d'un ou plusieurs processus enfants via la série d'attente d'appels système (tels que wait4, waitid) et obtenir ses informations de sortie. Ensuite, la série d'appels système en attente libérera également le corps du processus enfant (task_struct).
Lorsque le processus enfant se termine, le noyau enverra un signal à son processus parent pour notifier au processus parent de "récupérer le cadavre". Ce signal est par défaut SIGCHLD, mais ce signal peut être défini lors de la création d'un processus enfant via l'appel système clone.
Tant que le processus parent ne se termine pas, le processus enfant en état zombie existera toujours. Donc, si le processus parent se termine, qui « récupérera le cadavre » du processus enfant ?
Lorsqu'un processus se termine, tous ses processus enfants seront hébergés par d'autres processus (ce qui en fera des processus enfants d'autres processus). À qui est-il confié ? Il peut s'agir du processus suivant dans le groupe de processus du processus sortant (s'il en existe un) ou du processus numéro 1. Ainsi, chaque processus et chaque instant a un processus parent. Sauf si c'est le processus numéro 1.
Le processus n°1, le processus avec le pid 1, est également appelé processus d'initialisation. Après le démarrage du système Linux, le premier processus en mode utilisateur créé est le processus d'initialisation. Il a deux missions :
Exécuter le script d'initialisation du système et créer une série de processus (tous sont des descendants du processus init)
Attendre l'événement de sortie de son processus enfant dans une boucle infinie et call waitid L'appel système est utilisé pour terminer le travail de "collecte des cadavres" ; le processus
init ne sera pas suspendu ou tué (ceci est garanti par le noyau). Il est dans l'état TASK_INTERRUPTIBLE en attendant la sortie du processus enfant, et est dans l'état TASK_RUNNING pendant le processus de « récupération ».
X(TASK_DEAD - EXIT_DEAD) État de mort, le processus est sur le point d'être détruit
Et le processus peut ne pas conserver sa task_struct pendant le processus de sortie. Par exemple, ce processus est un processus détachable dans un programme multithread.
Ou le processus parent ignore explicitement le signal SIGCHLD en définissant le gestionnaire du signal SIGCHLD sur SIG_IGN. (Il s'agit d'une règle POSIX, bien que le signal de sortie du processus enfant puisse être défini sur un signal autre que SIGCHLD.)
À ce stade, le processus sera placé dans l'état de sortie EXIT_DEAD, ce qui signifie que le code suivant sera immédiatement Le processus est complètement libéré. L'état EXIT_DEAD est donc de très courte durée et presque impossible à capturer avec la commande ps.
L'état initial du processus
Le processus est créé via la série fork d'appels système (fork, clone, vfork). Le noyau (ou module noyau) peut également créer un processus noyau via la fonction kernel_thread. . Ces fonctions qui créent des sous-processus remplissent essentiellement la même fonction : copier le processus appelant pour obtenir un sous-processus. (Vous pouvez décider si diverses ressources sont partagées ou privées via les paramètres d'option.)
Donc puisque le processus appelant est dans l'état TASK_RUNNING (sinon, s'il n'est pas en cours d'exécution, comment peut-il être appelé ?), le processus enfant est également dans l'état TASK_RUNNING par défaut. De plus, l'appel système clone et la fonction noyau kernel_thread acceptent également l'option CLONE_STOPPED, définissant ainsi l'état initial du processus enfant sur TASK_STOPPED.
Modifications de l'état du processus
Une fois le processus créé, le statut peut subir une série de changements jusqu'à la fin du processus. Bien qu'il existe plusieurs états de processus, il n'existe que deux directions pour les changements d'état de processus : de l'état TASK_RUNNING à l'état non-TASK_RUNNING, ou de l'état non-TASK_RUNNING à l'état TASK_RUNNING.
En d'autres termes, si un signal SIGKILL est envoyé à un processus dans l'état TASK_INTERRUPTIBLE, le processus sera d'abord réveillé (entrera dans l'état TASK_RUNNING), puis sortira en réponse au signal SIGKILL (passage à l'état TASK_DEAD). Il ne sortira pas directement de l'état TASK_INTERRUPTIBLE.
Le processus passe de l'état non-TASK_RUNNING à l'état TASK_RUNNING par d'autres processus (qui peuvent également être des gestionnaires d'interruptions) effectuant des opérations de réveil. Le processus qui effectue l'éveil définit l'état du processus réveillé sur TASK_RUNNING, puis ajoute sa structure task_struct à la file d'attente exécutable d'un certain processeur. Ensuite, le processus éveillé aura la possibilité d’être programmé pour son exécution.
Il existe deux façons pour un processus de passer de l'état TASK_RUNNING à l'état non-TASK_RUNNING :
répondre au signal et entrer dans l'état TASK_STOPED ou TASK_DEAD
exécuter l'appel système et entrer activement dans l'état TASK_INTERRUPTIBLE ( tel que l'appel système nanosleep) ), ou l'état TASK_DEAD (comme l'appel système de sortie) ; ou parce que les ressources requises pour exécuter l'appel système ne peuvent pas être satisfaites, il entre dans l'état TASK_INTERRUPTIBLE ou l'état TASK_UNINTERRUPTIBLE (comme l'appel système select) ; appel).
Évidemment, ces deux situations ne peuvent se produire que si le processus s'exécute sur le CPU.
Description de l'état du processus Linux
Symbole d'état | Nom complet de l'état | Description |
---|---|---|
R | TASK_RUNNING | Ex Statut exécutable et statut d'exécution (statut dans la file d'attente run_queue) |
S | TASK_INTERRUPTIBLE | Peut gérer le signal |
D | TASK_UNINTERRUPTIBLE | Peut gérer le signal, il y a un retard | T
état de pause ou état de trace, le signal ne peut pas être traité, parce qu'il n'y a aucun intervalle de temps pour exécuter le code | Z | |
état de sortie, le processus devient un processus zombie. Il ne peut pas être tué, c'est-à-dire qu'il ne répond pas aux signaux de tâche et ne peut pas être tué avec SIGKILL |
Nous mettons le fait de mettre la task_struct (run_queue) de l'état d'exécution dans la file d'attente d'attente est appelé attente suspendue (le blocage). Le mettre de la file d'attente dans la file d'attente en cours d'exécution et être planifié par le CPU est appelé. réveiller le processus
Lorsqu'un processus est en cours d'exécution, parce que certaines de ses conditions de fonctionnement ne sont pas encore prêtes (par exemple, le réseau est requis mais la carte réseau est hors service, ou il doit attendre les IO, c'est-à-dire il doit utiliser des périphériques), il sera placé dans la file d'attente et les bits d'état de task_struct seront également modifiés pour S/D. Lorsque le processus est dans l'état S/D, il attend dans une file d'attente pour utiliser des périphériques (tels que des cartes réseau, des moniteurs de disque, etc.) La file d'attente en attente du CPU est appelée la file d'attente en cours d'exécution, et l'équipement en attente des périphériques est appelé la file d'attente Le soi-disant processus, lors de son exécution, peut se trouver dans différentes files d'attente en raison de besoins opérationnelsDans différentes files d'attente, le statut est différent Lorsqu'un processus est dans le R état, si Si vous avez besoin d'une sorte de périphérique, mais que le périphérique est utilisé, je changerai votre statut en S/D, puis je mettrai votre task_struct dans la file d'attenteRecommandations associées : "Tutoriel vidéo Linux
"Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!