processus en attente, processus de remplacement

Table des matières

processus en attente

fonction waitpid

fonction d'attente

remplacement de processus


processus en attente

Signification de processus en attente

Si le processus enfant se termine, si le processus parent l'ignore, cela peut provoquer un problème de "processus zombie", qui à son tour provoque une fuite de mémoire. De plus, une fois qu'un processus devient un zombie, il est invulnérable, et le "tuer sans clignoter" kill -9 ne peut rien faire, car personne ne peut tuer un processus mort. Enfin, nous devons savoir comment les tâches assignées par le processus parent au processus enfant sont accomplies. Par exemple, si le processus enfant finit de s'exécuter, si le résultat est correct ou non, ou s'il se termine normalement. Le processus parent doit récupérer les ressources du processus enfant et obtenir les informations de sortie du processus enfant au moyen d'une attente de processus.

fonction waitpid

#include <sys/types.h>

#include <sys/wait.h>

pid_ t waitpid(pid_t pid, int *status, int options);

valeur de retour :

  • Lors d'un retour normal, waitpid renvoie le processus PID du processus enfant collecté ;
  • Si l'option WNOHANG est définie et que waitpid trouve qu'il n'y a pas de processus enfants à collecter pendant l'appel, il renvoie 0 ;
  • S'il y a une erreur dans l'appel, -1 est renvoyé et errno sera défini sur la valeur correspondante pour indiquer l'erreur ;

paramètre:

1. pid (pour déterminer les membres de l'ensemble en attente) :

Si pid=-1, alors l'ensemble en attente est composé des processus enfants appartenant au processus parent. Équivalent à attendre.

Si pid > 0, alors le jeu d'attente est un processus enfant unique dont l'ID de processus est égal à pid.

2. status (modifier le comportement par défaut) :

Si le paramètre d'état n'est pas nul, alors waitpid placera des informations d'état sur l'état du processus enfant qui a provoqué le retour. Le fichier d'en-tête wait.h définit plusieurs macros qui interprètent le paramètre status :

  • WIFEXITED(status) : renvoie vrai si le processus enfant s'est terminé normalement en appelant exit ou un retour (retour).
  • WEXITSTATUS(status) : renvoie le statut de sortie d'un processus enfant normalement terminé. Ce statut n'est défini que lorsque WIFEXITED() renvoie true.
  • WIFSIGNALED(status) : Renvoie true si le processus enfant s'est terminé en raison d'un signal non intercepté.
  • WTERMSIG( status) : Renvoie le numéro du signal qui a provoqué l'arrêt du processus enfant. Cet état n'est défini que si WIFSIGNALED() renvoie vrai.
  • WIFSTOPPED(status) : renvoie vrai si le processus enfant qui a provoqué le retour est actuellement arrêté.
  • WSTOPSIG(status) : renvoie le numéro du signal qui a provoqué l'arrêt du processus enfant. Cet état n'est défini que si WIFSTOPPED() renvoie true.
  • WIFCONTINUED(status) : renvoie vrai si le processus enfant reçoit un signal SIGCONT pour redémarrer.

Si le processus appelant n'a pas d'enfant, waitpid renvoie -1 et définit errno sur ECHILD. Si la fonction waitpid est interrompue par un signal, elle renvoie -1 et définit errno sur EINTR.

3. options (vérifier le statut de sortie du processus fils recyclé) :

Le comportement par défaut peut être modifié en définissant des options sur diverses combinaisons des constantes WNOHANG, WUNTRACED et WCONTINUED :

  • WNOHANG : si un processus enfant du jeu d'attente ne s'est pas terminé, il revient immédiatement (la valeur de retour est 0). Le comportement par défaut consiste à suspendre le processus appelant jusqu'à ce qu'un processus enfant se termine. Cette option est utile si vous souhaitez effectuer un travail utile en attendant la fin du processus enfant.
  • WUNJTRACED : suspend l'exécution du processus appelant jusqu'à ce que l'un des processus du jeu d'attente se termine ou soit arrêté. Le PID renvoyé est le PID du processus enfant terminé ou arrêté qui a provoqué le retour. Le comportement par défaut consiste à renvoyer uniquement les processus enfants terminés. Cette option est utile lorsque vous souhaitez inspecter les processus enfants terminés et arrêtés.
  • WCONTINUED : suspend l'exécution du processus appelant jusqu'à ce qu'un processus en cours d'exécution dans l'ensemble en attente se termine ou qu'un processus arrêté dans l'ensemble en attente reçoive un signal SIGCONT pour redémarrer l'exécution.

    Ces options peuvent être combinées à l'aide de l'opération OR. Par exemple:

  • WNOHANG | WUNTRACED : renvoie immédiatement, si aucun des processus enfants de l'ensemble en attente n'est arrêté ou terminé, la valeur de retour est 0 ; s'il y en a un qui est arrêté ou terminé, la valeur de retour est le PID du processus enfant.

fonction d'attente

La fonction wait est une version simplifiée de la fonction waitpid.

#include <sys/types.h>

#include <sys/wait.h>

pid_t attendre (int * statut);  

Valeur de retour : renvoie le pid du processus attendu avec succès, renvoie -1 en cas d'échec.

Paramètres : paramètres de sortie, obtenez l'état de sortie du processus enfant, si vous ne vous en souciez pas, vous pouvez le définir sur NULL

Appeler wait(&status) est équivalent à appeler waitpid(-1,&status,0).

Si le processus enfant est déjà terminé, lors de l'appel de wait/waitpid, wait/waitpid reviendra immédiatement, libérera des ressources et obtiendra les informations de sortie du processus enfant.

Si à tout moment wait/waitpid est appelé, le processus enfant existe et s'exécute normalement, le processus peut se bloquer.

Si le sous-processus n'existe pas, une erreur est renvoyée immédiatement.

Le processus parent stocke les PID de ses enfants dans l'ordre, puis attend chaque enfant dans le même ordre en appelant waitpid avec le PID approprié comme premier argument. 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
 #define N 2
int main()
{                                                                                                                                                                                           
  int status,i;
   pid_t pid[N],retpid;
    //Parent creates N children
   for(i=0;i<N;i++)
      if((pid[i] = fork()) == 0)//child
       exit(100+i);

     //Parent reaps N children in order
     i=0;
    while((retpid = waitpid(pid[i++],&status,0)) > 0)
    {
         if(WIFEXITED(status))
           printf("child %d terminated normally with exit status=%d\n",retpid,WEXITSTATUS(status));
         else 
           printf("child %d terminated abnormally\n",retpid);
     }
 
     the only normal termination is if there are no more children
    if(errno != ECHILD)
      unix_error("waitpid error");
  
     exit(0);                                                       
 } 

Lorsque le processus enfant ne se termine pas, le processus parent attend toujours que le processus enfant se termine. Pendant la période d'attente, le processus parent ne peut rien faire. Ce type d'attente est appelé attente bloquante.

En fait, nous pouvons laisser le processus parent effectuer certaines de ses propres actions en attendant que le processus enfant se termine, puis lire les informations de sortie du processus enfant lorsque le processus enfant se termine, c'est-à-dire une attente non bloquante.

A ce stade, nous pouvons utiliser le paramètre options :

WNOHANG : Si un processus enfant du jeu d'attente ne s'est pas terminé, alors retour immédiat (la valeur de retour est 0). Le comportement par défaut consiste à suspendre le processus appelant jusqu'à ce qu'un processus enfant se termine. Cette option est utile si vous souhaitez effectuer un travail utile en attendant la fin du processus enfant.

#include <stdio.h> 
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
	pid_t pid;
	pid = fork();
	if (pid < 0) {
		printf("%s fork error\n", __FUNCTION__);
		return 1;
	}
	else if (pid == 0) { //child
		printf("child is run, pid is : %d\n", getpid());
		sleep(5);
		exit(1);
	}
	else {
		int status = 0;
		pid_t ret = 0;
		do
		{
			ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待
			if (ret == 0) {
				printf("child is running\n");
			}
			sleep(1);
		} while (ret == 0);
		if (WIFEXITED(status) && ret == pid) {
			printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));
		}
		else {
			printf("wait child failed, return.\n");
			return 1;
		}
	}
	return 0;
}

remplacement de processus

exec est une fonction de remplacement de programme et ne crée pas de processus lui-même. Le processus généré par exec est une copie identique du processus actuel et le pid n'a pas changé.

remplacer la fonction

int execve(const char *path, char *const argv[], char *const envp[]);

Ne renvoie rien en cas de succès, -1 en cas d'erreur. 

#include <unistd.h>

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg, ...,char *const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

Seul execve est un véritable appel système, et les autres fonctions sont l'encapsulation de la fonction execve, et finalement appellent execve.

Ces prototypes de fonctions semblent être faciles à confondre, mais il est facile de s'en souvenir tant que vous maîtrisez les règles.

l(list) : Indique que le paramètre adopte une liste ;

v(vecteur) : tableau pour les paramètres ;

p(path) : il y a p pour rechercher automatiquement la variable d'environnement PATH ;

e(env) : Indique qu'il maintient lui-même les variables d'environnement 

execl : le format du paramètre est une liste ; sans chemin ; utilisez la variable d'environnement actuelle.

execlp : le format du paramètre est une liste ; avec un chemin ; vous devez assembler vous-même les variables d'environnement.

execle : le format du paramètre est une liste ; sans chemin ; utilisez la variable d'environnement actuelle.

execv : le format du paramètre est un tableau ; sans chemin ; utilisez la variable d'environnement actuelle.

execvp : le format du paramètre est un tableau ; avec un chemin ; vous devez assembler vous-même les variables d'environnement.

Nous pouvons voir que la fin... imprimée plus tard n'est pas sortie. Lorsqu'un processus appelle une fonction exec, le code de l'espace utilisateur et les données du processus sont complètement remplacés par le nouveau programme, et l'exécution commence à partir de la routine de démarrage du nouveau programme. Le code suivant appartient à l'ancien code et est directement remplacé, et ne sera plus exécuté. 

 

#include <unistd.h>

int main()

{

        char *const argv[] = {"ls", "-l", NULL} ;

        char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL} ;

        execl("/bin/ls", "ls", "-l", NULL); // avec p, vous pouvez utiliser la variable d'environnement PATH, pas besoin d'écrire le chemin complet execlp("ls", "ls" , "-l ", NULL); // Pour ceux avec e, vous devez assembler vous-même les variables d'environnement

        execle("ls", "ls", "-l", NULL, envp);

        execv("/bin/ls", argv); // avec p, vous pouvez utiliser la variable d'environnement PATH, pas besoin d'écrire le chemin complet

        execvp("ls", argv); // Pour ceux avec e, vous devez assembler vous-même les variables d'environnement

        execve("/bin/ls", argv, envp);

        sortie(0);

}  

 

 Le dernier élément du tableau est de préférence vide.

 

Je suppose que tu aimes

Origine blog.csdn.net/m0_55752775/article/details/130296320
conseillé
Classement