Use a função waitpid em C
-
Use a função
waitpid
para monitorar o status do processo filho em C - Use macros para exibir o status de espera do processo filho em C
Este artigo demonstrará vários métodos sobre como usar a função waitpid
em C.
Use a função waitpid
para monitorar o status do processo filho em C
Em sistemas baseados em Unix, existe a noção de um processo que é simplesmente uma instância em execução de um programa. O processo pode criar outros processos usando a chamada de sistema fork
e executar a parte dada do código. Observe que, para este tópico, as chamadas do sistema são serviços do sistema operacional fornecidos ao usuário como funções do tipo C. Geralmente, em muitos cenários, um programa é necessário para monitorar os processos que ele criou, chamados filhos. A família de funções wait
é aquela que fornece esta funcionalidade e waitpid
é uma delas.
A chamada de sistema wait
tem múltiplas limitações e, para cobrir recursos mais avançados, a função waitpid
deve ser utilizada. Ou seja, se um processo cria vários filhos e o pai precisa monitorar um filho específico, apenas waitpid
pode fazer isso. No exemplo a seguir, implementamos uma função chamada spawnChild
que cria um novo processo filho e executa um programa diferente. Para uma boa demonstração do exemplo, estamos executando um programa top
(disponível em quase todos os sistemas baseados em Unix) que está em execução até que o usuário o encerre. Uma vez que a função retorna no processo pai, armazenamos um ID do processo filho e o passamos para a função waitpid
para monitorar o status.
O waitpid
leva três argumentos, o primeiro dos quais é o número de identificação do processo (pid). O PID pode ter vários valores predefinidos com diferentes efeitos, mas, neste caso, vamos apenas mencionar -1
e >0
. O valor -1
pode ser passado para monitorar qualquer processo filho que muda seu estado primeiro, que é usado para implementar a funcionalidade wait
. >0
implica que o valor deve ser o ID do processo real que foi retornado da função fork
, que por sua vez é usado para monitorar apenas o processo filho específico. O segundo argumento é do tipo ponteiro int
e devemos declarar uma variável inteira para passar seu endereço para a função. waitpid
, por outro lado, irá armazenar as informações de status do filho na variável int
fornecida, que então pode ser decodificada usando as macros predefinidas. O último argumento é do tipo int
e é usado para especificar determinados eventos de processo filho a serem monitorados, além dos padrões.
#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);
}
Use macros para exibir o status de espera do processo filho em C
Observe que o processo pai é suspenso quando a função waitpid
é chamada e não retoma a execução até que o processo filho monitorado mude de estado. O próximo exemplo mostra a chamada waitpid
com os argumentos WUNTRACED
e WCONTINUED
, o que implica que um pai monitora se o filho foi interrompido ou continuado por sinais correspondentes. Além disso, implementamos a função printWaitStatus
que pode ser chamada para imprimir o status do filho recuperado. Observe que ele está usando macros do tipo W*
definidas no cabeçalho <sys/wait.h>
para extrair as informações codificadas da variável inteira status
.
Existem algumas definições de pré-processador condicionais, uma vez que nem todas as macros estão disponíveis em todas as plataformas, garantindo assim que a função é portátil e compila com êxito independentemente.
#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