Verwendung der waitpid-Funktion in C

Jinku Hu 12 Oktober 2023
  1. Verwendung von die Funktion waitpid zur Überwachung des Status von Kindprozessen in C
  2. Makros verwenden, um den Wartestatus des Kindprozesses in C anzuzeigen
Verwendung der waitpid-Funktion in C

Dieser Artikel demonstriert mehrere Methoden zur Verwendung der Funktion waitpid in C.

Verwendung von die Funktion waitpid zur Überwachung des Status von Kindprozessen in C

In Unix-basierten Systemen gibt es den Begriff des Prozesses, der einfach eine laufende Instanz eines Programms ist. Der Prozess kann mit dem Systemaufruf fork andere Prozesse erzeugen und den angegebenen Teil des Codes ausführen. Beachten Sie, dass Systemaufrufe für dieses Thema Dienste des Betriebssystems sind, die dem Benutzer als Funktionen im C-Stil zur Verfügung gestellt werden. Im Allgemeinen wird in vielen Szenarien von einem Programm verlangt, dass es von ihm erzeugte Prozesse, sogenannte Children, überwacht. Die wait-Funktionsfamilie ist diejenige, die diese Funktionalität bereitstellt, und waitpid ist eine von ihnen.

Der Systemaufruf wait hat mehrere Einschränkungen, und um weitergehende Funktionen abzudecken, muss die Funktion waitpid verwendet werden. Wenn nämlich ein Prozess mehrere Kinder erzeugt und der Elternprozess ein bestimmtes Kind überwachen muss, kann dies nur mit waitpid geschehen. Im folgenden Beispiel implementieren wir eine Funktion namens spawnChild, die einen neuen Kindprozess erzeugt und ein anderes Programm ausführt. Um das Beispiel gut zu demonstrieren, führen wir ein top-Programm aus (das auf fast allen Unix-basierten Systemen verfügbar ist), das so lange läuft, bis der Benutzer es beendet. Sobald die Funktion im Elternprozess zurückkehrt, speichern wir eine Kindprozess-ID und übergeben sie an die Funktion waitpid, um den Status zu überwachen.

Die Funktion waitpid nimmt drei Argumente entgegen, von denen das erste die Prozess-ID-Nummer (pid) ist. PID kann mehrere vordefinierte Werte mit unterschiedlichen Auswirkungen haben, aber in diesem Fall werden wir nur -1 und >0 erwähnen. Der Wert -1 kann übergeben werden, um jeden Kindprozess zu überwachen, der seinen Zustand zuerst ändert, was zur Implementierung der wait-Funktionalität verwendet wird. >0 impliziert, dass der Wert die tatsächliche Prozess-ID sein sollte, die von der Funktion fork zurückgegeben wurde, was wiederum verwendet wird, um nur bestimmte Kindprozesse zu überwachen. Das zweite Argument ist vom Typ int Zeiger und wir sollten eine Integer-Variable deklarieren, um seine Adresse an die Funktion zu übergeben. Die Funktion waitpid hingegen speichert die Statusinformationen des Kindprozesses in der angegebenen int-Variablen, die dann mit Hilfe der vordefinierten Makros dekodiert werden können. Das letzte Argument ist vom Typ int und wird verwendet, um die bestimmten Ereignisse der Kindprozesse anzugeben, die zusätzlich zu den Standardereignissen überwacht werden sollen.

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

Makros verwenden, um den Wartestatus des Kindprozesses in C anzuzeigen

Beachten Sie, dass der Elternprozess angehalten wird, wenn die Funktion waitpid aufgerufen wird, und die Ausführung erst wieder aufnimmt, wenn der überwachte Kindprozess seinen Zustand ändert. Das nächste Beispiel zeigt den waitpid-Aufruf mit den Argumenten WUNTRACED und WCONTINUED, was bedeutet, dass ein Elternprozess durch entsprechende Signale überwacht, ob der Kindprozess angehalten oder fortgesetzt wurde. Außerdem haben wir die Funktion printWaitStatus implementiert, die aufgerufen werden kann, um den abgerufenen Child-Status zu drucken. Beachten Sie, dass sie Makros vom Typ W* verwendet, die im Header <sys/wait.h> definiert sind, um die kodierten Informationen aus der Integer-Variablen status zu extrahieren.

Es gibt einige bedingte Präprozessor-Definitionen, da nicht alle Makros auf allen Plattformen verfügbar sind, wodurch sichergestellt wird, dass die Funktion portabel ist und unabhängig davon erfolgreich kompiliert werden kann.

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