Tuer un processus enfant en C

Jinku Hu 12 octobre 2023
  1. Utilisez le signal SIGKILL pour terminer un processus enfant en C
  2. Utiliser le signal SIGTERM pour terminer un processus enfant en C
Tuer un processus enfant en C

Cet article présente plusieurs méthodes sur la façon de tuer un processus enfant dans C.

Utilisez le signal SIGKILL pour terminer un processus enfant en C

Il existe plusieurs signaux conçus pour terminer un processus lors de sa livraison, mais l’envoi du signal SIGKILL est la méthode la plus puissante et la plus sûre pour le faire. Généralement, un programme peut enregistrer des fonctions spéciales appelées gestionnaires de signaux qui sont invoquées automatiquement une fois que le signal correspondant est délivré au programme. L’utilisateur implémente le code de fonction du gestionnaire qui effectue généralement des travaux de nettoyage pour le programme. Outre les gestionnaires de fonctions, il peut y avoir des actions par défaut sur les signaux délivrés comme le blocage et l’ignorance. Cependant, le signal SIGKILL ne peut pas être ignoré, bloqué ou traité par la fonction donnée. Ainsi, cette méthode doit être le dernier recours lorsque vous essayez de terminer un processus.

Le signal SIGKILL peut être envoyé avec un appel système kill. Notez cependant que le gestionnaire SIGTERM inscrit dans l’exemple de code suivant ne peut pas attraper le SIGKILL livré, et il tue immédiatement le processus enfant donné.

Le programme suivant engendre un processus enfant et y inscrit le gestionnaire SIGTERM. Ensuite, le processus fils exécute une boucle infinie à moins que le signal ne soit délivré, ce qui retourne la variable d’expression while. Par conséquent, le signal SIGKILL délivré par le parent n’invoque pas le gestionnaire et termine instantanément le processus fils.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

volatile sig_atomic_t shutdown_flag = 1;

void cleanupRoutine(int signal_number) { shutdown_flag = 0; }

int main(void) {
  int wstatus;

  pid_t c_pid = fork();
  if (c_pid == -1) {
    perror("fork");
    exit(EXIT_FAILURE);
  }

  if (c_pid == 0) {
    printf("printed from child process - %d\n", getpid());

    int count = 0;

    struct sigaction sigterm_action;
    memset(&sigterm_action, 0, sizeof(sigterm_action));
    sigterm_action.sa_handler = &cleanupRoutine;
    sigterm_action.sa_flags = 0;

    // Mask other signals from interrupting SIGTERM handler
    if (sigfillset(&sigterm_action.sa_mask) != 0) {
      perror("sigfillset");
      exit(EXIT_FAILURE);
    }
    // Register SIGTERM handler
    if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
      perror("sigaction SIGTERM");
      exit(EXIT_FAILURE);
    }

    while (shutdown_flag) {
      count += 1;
    }
    printf("count = %d\n", count);

    exit(EXIT_SUCCESS);
  } else {
    printf("printed from parent process - %d\n", getpid());
    int ret;

    sleep(5);

    ret = kill(c_pid, SIGKILL);
    if (ret == -1) {
      perror("kill");
      exit(EXIT_FAILURE);
    }

    if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
      perror("waitpid");
      exit(EXIT_FAILURE);
    }
  }

  exit(EXIT_SUCCESS);
}

Utiliser le signal SIGTERM pour terminer un processus enfant en C

Alternativement, un processus fils peut être arrêté en utilisant le signal SIGTERM, qui peut être géré par le programme. L’échantillon de code suivant répète l’implémentation du programme précédent sauf qu’il remplace le signal SIGKILL par SIGTERM. La fonction sigfillset est utilisée pour empêcher d’autres signaux d’interrompre l’exécution de la fonction de gestionnaire enregistrée. Le code du gestionnaire modifie la variable globale de type sig_atomic_t qui arrête la boucle while dans le processus fils et imprime la valeur de la variable count. Attention cependant, il est toujours préférable d’utiliser l’appel sigaction au-dessus de la fonction signal lors de l’enregistrement des gestionnaires, car cette dernière n’est pas spécifiée en détail par le standard POSIX.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

volatile sig_atomic_t shutdown_flag = 1;

void cleanupRoutine(int signal_number) { shutdown_flag = 0; }

int main(void) {
  int wstatus;

  pid_t c_pid = fork();
  if (c_pid == -1) {
    perror("fork");
    exit(EXIT_FAILURE);
  }

  if (c_pid == 0) {
    printf("printed from child process - %d\n", getpid());

    int count = 0;
    struct sigaction sigterm_action;
    memset(&sigterm_action, 0, sizeof(sigterm_action));
    sigterm_action.sa_handler = &cleanupRoutine;
    sigterm_action.sa_flags = 0;

    // Mask other signals from interrupting SIGTERM handler
    if (sigfillset(&sigterm_action.sa_mask) != 0) {
      perror("sigfillset");
      exit(EXIT_FAILURE);
    }
    // Register SIGTERM handler
    if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
      perror("sigaction SIGTERM");
      exit(EXIT_FAILURE);
    }

    while (shutdown_flag) {
      count += 1;
    }
    printf("count = %d\n", count);

    exit(EXIT_SUCCESS);
  } else {
    printf("printed from parent process - %d\n", getpid());
    int ret;

    sleep(5);

    ret = kill(c_pid, SIGTERM);
    if (ret == -1) {
      perror("kill");
      exit(EXIT_FAILURE);
    }

    if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
      perror("waitpid");
      exit(EXIT_FAILURE);
    }
  }

  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