Einen Kindprozess beenden in C

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie das Signal SIGKILL, um einen Kindprozess in C zu beenden
  2. Verwenden Sie das Signal SIGTERM, um einen untergeordneten Prozess in C zu beenden
Einen Kindprozess beenden in C

Dieser Artikel demonstriert mehrere Methoden, wie man einen Kindprozess in C beenden kann.

Verwenden Sie das Signal SIGKILL, um einen Kindprozess in C zu beenden

Es gibt mehrere Signale, die einen Prozess bei seiner Übermittlung beenden sollen. Das Senden des Signals SIGKILL ist jedoch die leistungsstärkste und sicherste Methode, um dies zu tun. Im Allgemeinen kann ein Programm spezielle Funktionen registrieren, die als Signalhandler bezeichnet werden und automatisch aufgerufen werden, sobald das entsprechende Signal an das Programm geliefert wird. Der Benutzer implementiert den Handler-Funktionscode, der normalerweise einige Bereinigungsarbeiten für das Programm ausführt. Abgesehen von Funktionshandlern kann es Standardaktionen für gelieferte Signale wie Blockieren und Ignorieren geben. Das Signal SIGKILL kann jedoch von der angegebenen Funktion nicht ignoriert, blockiert oder verarbeitet werden. Daher sollte diese Methode der letzte Ausweg sein, wenn versucht wird, einen Prozess zu beenden.

Das Signal SIGKILL kann mit einem Systemaufruf kill gesendet werden. Beachten Sie jedoch, dass der im folgenden Codebeispiel registrierte Handler SIGTERM den gelieferten SIGKILL nicht abfangen kann und den angegebenen untergeordneten Prozess sofort beendet.

Das folgende Programm erzeugt einen untergeordneten Prozess und registriert den Handler SIGTERM darin. Dann führt der untergeordnete Prozess eine Endlosschleife aus, es sei denn, das Signal wird geliefert, wodurch die Ausdrucksvariable while umgedreht wird. Folglich ruft das vom Elternteil übermittelte Signal SIGKILL den Handler nicht auf und beendet den untergeordneten Prozess sofort.

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

Verwenden Sie das Signal SIGTERM, um einen untergeordneten Prozess in C zu beenden

Alternativ kann ein untergeordneter Prozess mit dem Signal SIGTERM beendet werden, das vom Programm verarbeitet werden kann. Das nächste Codebeispiel wiederholt die vorherige Programmimplementierung, außer dass das Signal SIGKILL durch SIGTERM ersetzt wird. Mit der Funktion sigfillset wird verhindert, dass andere Signale die Ausführung der registrierten Handlerfunktion unterbrechen. Der Handlercode ändert die globale Variable vom Typ sig_atomic_t, die die Schleife while im untergeordneten Prozess stoppt und den Wert der Variablen count druckt. Beachten Sie jedoch, dass es bei der Registrierung der Handler immer besser ist, den Aufruf sigaction über der Funktion signal zu verwenden, da letzterer im POSIX-Standard nicht im Detail festgelegt ist.

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

Verwandter Artikel - C Process