Utilice la función waitpid en C
-
Utilice la función
waitpid
para monitorear el estado del proceso secundario en C - Utilice macros para mostrar el estado de espera del proceso secundario en C
Este artículo demostrará varios métodos sobre cómo utilizar la función waitpid
en C.
Utilice la función waitpid
para monitorear el estado del proceso secundario en C
En los sistemas basados en Unix, existe una noción de proceso que es simplemente una instancia en ejecución de un programa. El proceso puede crear otros procesos usando la llamada al sistema fork
y ejecutar la porción dada del código. Tenga en cuenta que, para este tema, las llamadas al sistema son servicios del sistema operativo que se proporcionan al usuario como funciones de estilo C. Generalmente, en muchos escenarios, se requiere un programa para monitorear los procesos que creó llamados hijos. La familia de funciones wait
es la que proporciona esta funcionalidad, y waitpid
es una de ellas.
La llamada del sistema wait
tiene múltiples limitaciones y, para cubrir funciones más avanzadas, es necesario utilizar la función waitpid
. Es decir, si un proceso crea varios hijos y el padre necesita supervisar a un hijo específico, solo waitpid
puede hacer esto. En el siguiente ejemplo, implementamos una función llamada spawnChild
que crea un nuevo proceso hijo y ejecuta un programa diferente. En aras de una buena demostración del ejemplo, estamos ejecutando un programa top
(disponible en casi todos los sistemas basados en Unix) que se está ejecutando hasta que el usuario lo termina. Una vez que la función regresa al proceso padre, almacenamos un ID de proceso hijo y lo pasamos a la función waitpid
para monitorear el estado.
El waitpid
toma tres argumentos, el primero de los cuales es el número de identificación del proceso (pid). PID puede tener múltiples valores prediseñados con diferentes efectos, pero en este caso, solo vamos a mencionar -1
y >0
. El valor -1
se puede pasar para monitorear cualquier proceso hijo que cambie su estado primero, que se usa para implementar la funcionalidad wait
. >0
implica que el valor debe ser el ID de proceso real que se devolvió desde la función fork
, que a su vez se usa para monitorear solo un proceso hijo específico. El segundo argumento es de tipo puntero int
y debemos declarar una variable entera para pasar su dirección a la función. waitpid
, por otro lado, almacenará la información del estado del niño en la variable int
dada, que luego se puede decodificar usando las macros predefinidas. El último argumento es de tipo int
, y se usa para especificar ciertos eventos de proceso hijo a monitorear además de los predeterminados.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t spawnChild(const char* program, char** arg_list) {
pid_t ch_pid = fork();
if (ch_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (ch_pid > 0) {
printf("spawn child with pid - %d\n", ch_pid);
return ch_pid;
} else {
execvp(program, arg_list);
perror("execve");
exit(EXIT_FAILURE);
}
}
int main(void) {
const char* args[] = {"top", NULL, NULL};
pid_t child;
int wstatus;
child = spawnChild("top", args);
if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Utilice macros para mostrar el estado de espera del proceso secundario en C
Tenga en cuenta que el proceso padre se suspende cuando se llama a la función waitpid
y no reanuda la ejecución hasta que el proceso hijo supervisado cambia de estado. El siguiente ejemplo muestra la llamada waitpid
con los argumentos WUNTRACED
y WCONTINUED
, lo que implica que un padre supervisa si el hijo ha sido detenido o continuado por las señales correspondientes. Además, implementamos la función printWaitStatus
que se puede llamar para imprimir el estado secundario recuperado. Observe que está usando macros de tipo W*
definidas en el encabezado <sys/wait.h>
para extraer la información codificada de la variable entera status
.
Hay algunas definiciones de preprocesador condicionales, ya que no todas las macros están disponibles en todas las plataformas, lo que garantiza que la función sea portátil y se compile correctamente independientemente.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t spawnChild(const char* program, char** arg_list) {
pid_t ch_pid = fork();
if (ch_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (ch_pid > 0) {
printf("spawn child with pid - %d\n", ch_pid);
return ch_pid;
} else {
execvp(program, arg_list);
perror("execve");
exit(EXIT_FAILURE);
}
}
void printWaitStatus(int status) {
if (WIFEXITED(status)) {
printf("child exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("child killed by signal %d (%s)", WTERMSIG(status),
strsignal(WTERMSIG(status)));
#ifdef WCOREDUMP
if (WCOREDUMP(status)) printf(" (core dumped)");
#endif
printf("\n");
} else if (WIFSTOPPED(status)) {
printf("child stopped by signal %d (%s)\n", WSTOPSIG(status),
strsignal(WSTOPSIG(status)));
#ifdef WIFCONTINUED
} else if (WIFCONTINUED(status)) {
printf("child continued\n");
#endif
} else {
printf("status=%x\n", (unsigned int)status);
}
}
int main(void) {
const char* args[] = {"top", NULL, NULL};
pid_t child;
int wstatus;
child = spawnChild("top", args);
if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
printWaitStatus(wstatus);
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook