proceso en espera, reemplazo de proceso

Tabla de contenido

proceso en espera

función de espera

función de espera

proceso de reemplazo


proceso en espera

Significado de proceso en espera

Si el proceso secundario finaliza, si el proceso principal lo ignora, puede causar un problema de "proceso zombi", que a su vez provoca una pérdida de memoria. Además, una vez que un proceso se convierte en zombi, es invulnerable, y el "matar sin parpadear" kill -9 no puede hacer nada, porque nadie puede matar un proceso muerto. Finalmente, necesitamos saber cómo se completan las tareas asignadas por el proceso padre al proceso hijo. Por ejemplo, si el proceso hijo termina de ejecutarse, si el resultado es correcto o no, o si sale normalmente. El proceso padre necesita reclamar los recursos del proceso hijo y obtener la información de salida del proceso hijo por medio del proceso en espera.

función de espera

#include <sys/tipos.h>

#incluir <sys/esperar.h>

pid_ t waitpid(pid_t pid, int *estado, int opciones);

valor de retorno:

  • Cuando regresa normalmente, waitpid devuelve el PID del proceso secundario recopilado;
  • Si se establece la opción WNOHANG y waitpid encuentra que no hay procesos secundarios finalizados para recopilar durante la llamada, devuelve 0;
  • Si hay un error en la llamada, se devuelve -1 y errno se establecerá en el valor correspondiente para indicar el error;

parámetro:

1. pid (para determinar los miembros del conjunto de espera) :

Si pid=-1, el conjunto de espera se compone de los procesos secundarios que pertenecen al proceso principal. Equivale a esperar.

Si pid > 0, entonces el conjunto de espera es un único proceso secundario cuyo ID de proceso es igual a pid.

2. estado (modificar el comportamiento predeterminado) :

Si el parámetro de estado no es nulo, waitpid incluirá información de estado sobre el estado del proceso secundario que provocó la devolución. El archivo de encabezado wait.h define varias macros que interpretan el parámetro de estado:

  • WIFEXITED(status): devuelve verdadero si el proceso secundario finalizó normalmente llamando a exit o return (return).
  • WEXITSTATUS(status): Devuelve el estado de salida de un proceso secundario normalmente terminado.Este estado solo se define cuando WIFEXITED() devuelve verdadero.
  • WIFSIGNALED(status): devuelve verdadero si el proceso secundario finalizó debido a una señal no detectada.
  • WTERMSIG(estado): Devuelve el número de la señal que provocó la finalización del proceso secundario. Este estado solo se define si WIFSIGNALED() devuelve verdadero.
  • WIFSTOPPED(status): devuelve verdadero si el proceso secundario que provocó la devolución está actualmente detenido.
  • WSTOPSIG(status): Devuelve el número de la señal que provocó la detención del proceso secundario. Este estado solo se define si WIFSTOPPED() devuelve verdadero.
  • WIFCONTINUED(status): devuelve verdadero si el proceso secundario recibe una señal SIGCONT para reiniciar.

Si el proceso de llamada no tiene hijos, waitpid devuelve -1 y establece errno en ECHILD. Si la función waitpid es interrumpida por una señal, devuelve -1 y establece errno en EINTR.

3. opciones (verifique el estado de salida del proceso secundario reciclado) :

El comportamiento predeterminado se puede modificar configurando opciones para varias combinaciones de las constantes WNOHANG, WUNTRACED y WCONTINUED:

  • WNOHANG: si algún proceso secundario en el conjunto de espera no ha terminado, regrese inmediatamente (el valor de retorno es 0). El comportamiento predeterminado es suspender el proceso de llamada hasta que termine un proceso secundario. Esta opción es útil si desea realizar un trabajo útil mientras espera que finalice el proceso secundario.
  • WUNJTRACED: suspende la ejecución del proceso de llamada hasta que uno de los procesos en el conjunto de espera finaliza o se detiene. El PID devuelto es el PID del proceso secundario finalizado o detenido que provocó la devolución. El comportamiento predeterminado es devolver solo los procesos secundarios terminados. Esta opción es útil cuando desea inspeccionar procesos secundarios terminados y detenidos.
  • WCONTINUED: suspende la ejecución del proceso de llamada hasta que finaliza un proceso en ejecución en el conjunto de espera o un proceso detenido en el conjunto de espera recibe una señal SIGCONT para reiniciar la ejecución.

    Estas opciones se pueden combinar mediante la operación OR. Por ejemplo:

  • WNOHANG | WUNTRACED: regresa inmediatamente, si ninguno de los procesos secundarios en el conjunto de espera se detiene o finaliza, el valor de retorno es 0; si uno se detiene o finaliza, el valor de retorno es el PID del proceso secundario.

función de espera

La función de espera es una versión simple de la función waitpid.

#include <sys/tipos.h>

#incluir <sys/esperar.h>

pid_t espera(int*estado);  

Valor devuelto: Devuelve el pid del proceso que se espera con éxito, devuelve -1 si falla.

Parámetros: Parámetros de salida, obtenga el estado de salida del proceso secundario, si no le importa, puede establecerlo en NULL

Llamar a wait(&status) es equivalente a llamar a waitpid(-1,&status,0).

Si el proceso hijo ya salió, al llamar a wait/waitpid, wait/waitpid regresará inmediatamente, liberará recursos y obtendrá la información de salida del proceso hijo.

Si en algún momento se llama a wait/waitpid, el proceso secundario existe y se ejecuta normalmente, el proceso puede bloquearse.

Si el subproceso no existe, se devuelve un error inmediatamente.

El proceso padre almacena los PID de sus hijos en orden y luego espera a cada hijo en el mismo orden llamando a waitpid con el PID apropiado como primer argumento. 

#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);                                                       
 } 

Cuando el proceso secundario no finaliza, el proceso principal siempre está esperando que el proceso secundario finalice. Durante el período de espera, el proceso principal no puede hacer nada. Este tipo de espera se denomina espera de bloqueo.

De hecho, podemos dejar que el proceso principal realice algunas de sus propias cosas mientras espera que el proceso secundario finalice, y luego leer la información de salida del proceso secundario cuando el proceso secundario finaliza, es decir, espera sin bloqueo.

En este momento podemos usar el parámetro de opciones :

WNOHANG : si algún proceso secundario en el conjunto de espera no ha terminado, regrese inmediatamente (el valor de retorno es 0). El comportamiento predeterminado es suspender el proceso de llamada hasta que termine un proceso secundario. Esta opción es útil si desea realizar un trabajo útil mientras espera que finalice el proceso secundario.

#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;
}

proceso de reemplazo

exec es una función de reemplazo de programa y no crea un proceso en sí mismo. El proceso generado por exec es una copia idéntica del proceso actual, y el pid no ha cambiado.

función de reemplazo

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

No devuelve nada en caso de éxito, -1 en caso de error. 

#include <unistd.h>

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

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

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

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

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

Solo execve es una llamada al sistema real, y otras funciones son la encapsulación de la función execve y, finalmente, llamar a execve.

Estos prototipos de funciones parecen ser fáciles de confundir, pero son fáciles de recordar siempre y cuando domines las reglas.

l(lista) : Indica que el parámetro adopta una lista;

v(vector) : matriz de parámetros;

p(ruta): Hay p para buscar automáticamente la variable de entorno PATH;

e(env): Indica que mantiene las variables de entorno por sí mismo 

execl: el formato del parámetro es una lista; sin una ruta; use la variable de entorno actual.

execlp: el formato del parámetro es una lista; con una ruta; debe ensamblar las variables de entorno usted mismo.

execle: el formato del parámetro es una lista; sin ruta; use la variable de entorno actual.

execv: el formato del parámetro es una matriz; sin una ruta; use la variable de entorno actual.

execvp: el formato del parámetro es una matriz; con una ruta; debe ensamblar las variables de entorno usted mismo.

Podemos ver que no se emite el final... impreso más tarde.Cuando un proceso llama a una función exec, el código de espacio de usuario y los datos del proceso son completamente reemplazados por el nuevo programa, y ​​la ejecución comienza desde la rutina de inicio del nuevo programa. El siguiente código pertenece al código antiguo y se reemplaza directamente y no se volverá a ejecutar. 

 

#include <unistd.h>

int principal()

{

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

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

        execl("/bin/ls", "ls", "-l", NULL); // con p, puede usar la variable de entorno PATH, no es necesario escribir la ruta completa execlp("ls", "ls" , "-l ", NULL); // Para aquellos con e, debe ensamblar las variables de entorno usted mismo

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

        execv("/bin/ls", argv); // con p, puede usar la variable de entorno PATH, no es necesario escribir la ruta completa

        execvp("ls", argv); // Para aquellos con e, debe ensamblar las variables de entorno usted mismo

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

        salir(0);

}  

 

 El último elemento de la matriz está preferentemente vacío.

 

Supongo que te gusta

Origin blog.csdn.net/m0_55752775/article/details/130296320
Recomendado
Clasificación