Utilisez la fonction waitpid en C

Jinku Hu 12 octobre 2023
  1. Utilisez la fonction waitpid pour surveiller l’état du processus enfant en C
  2. Utiliser des macros pour afficher l’état d’attente du processus enfant en C
Utilisez la fonction waitpid en C

Cet article présente plusieurs méthodes d’utilisation de la fonction waitpid en C.

Utilisez la fonction waitpid pour surveiller l’état du processus enfant en C

Dans les systèmes Unix, il existe une notion de processus qui est simplement une instance en cours d’exécution d’un programme. Le processus peut créer d’autres processus en utilisant l’appel système fork et exécuter la partie donnée du code. Notez que, pour cette rubrique, les appels système sont des services de système d’exploitation fournis à l’utilisateur en tant que fonctions de style C. En règle générale, dans de nombreux scénarios, un programme doit surveiller les processus qu’il a créés appelés enfants. La famille de fonctions wait est celle qui fournit cette fonctionnalité, et waitpid en fait partie.

L’appel système wait a plusieurs limitations, et pour couvrir des fonctionnalités plus avancées, la fonction waitpid doit être utilisée. À savoir, si un processus crée plusieurs enfants et que le parent a besoin de surveiller un enfant spécifique, seul waitpid peut le faire. Dans l’exemple suivant, nous implémentons une fonction nommée spawnChild qui crée un nouveau processus enfant et exécute un programme différent. Pour une bonne démonstration de l’exemple, nous exécutons un programme top (disponible sur presque tous les systèmes basés sur Unix) qui est en cours d’exécution jusqu’à ce que l’utilisateur le termine. Une fois que la fonction revient dans le processus parent, nous stockons un ID de processus enfant et le passons à la fonction waitpid pour surveiller l’état.

Le waitpid prend trois arguments, dont le premier est le numéro d’identification du processus (pid). Le PID peut avoir plusieurs valeurs prédéfinies avec des effets différents, mais dans ce cas, nous n’allons mentionner que -1 et >0. La valeur -1 peut être transmise pour surveiller tout processus enfant qui change d’abord son état, ce qui est utilisé pour implémenter la fonctionnalité wait. > 0 implique que la valeur doit être l’ID de processus réel qui a été renvoyé par la fonction fork, qui à son tour est utilisée pour surveiller uniquement un processus enfant spécifique. Le deuxième argument est de type pointeur int et nous devons déclarer une variable entière pour passer son adresse à la fonction. waitpid, d’autre part, stockera les informations sur l’état de l’enfant dans la variable int donnée, qui peut ensuite être décodée en utilisant les macros prédéfinies. Le dernier argument est de type int, et il est utilisé pour spécifier certains événements de processus enfant à surveiller en plus de ceux par défaut.

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

Utiliser des macros pour afficher l’état d’attente du processus enfant en C

Notez que le processus parent est suspendu lorsque la fonction waitpid est appelée et qu’il ne reprend pas l’exécution tant que le processus enfant surveillé ne change pas d’état. L’exemple suivant montre l’appel waitpid avec les arguments WUNTRACED et WCONTINUED, ce qui implique qu’un parent surveille si l’enfant a été arrêté ou poursuivi par les signaux correspondants. De plus, nous avons implémenté la fonction printWaitStatus qui peut être appelée pour imprimer l’état de l’enfant récupéré. Notez qu’il utilise des macros de type W* définies dans l’en-tête <sys/wait.h> pour extraire les informations codées de la variable entière status.

Il existe des définitions de préprocesseur conditionnelles car toutes les macros ne sont pas disponibles sur toutes les plates-formes, garantissant ainsi que la fonction est portable et se compile avec succès malgré tout.

#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);
}
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Article connexe - C Process