使用 C 語言中的 waitpid 函式

Jinku Hu 2023年1月30日 2021年2月28日
  1. 在 C 語言中使用 waitpid 函式監控子程序狀態
  2. 在 C 語言中使用巨集來顯示子程序的等待狀態
使用 C 語言中的 waitpid 函式

本文將演示關於如何使用 C 語言中的 waitpid 函式的多種方法。

在 C 語言中使用 waitpid 函式監控子程序狀態

在基於 Unix 的系統中,有一個程序的概念,它只是一個程式的執行例項。該程序可以使用 fork 系統呼叫建立其他程序,並執行給定的部分程式碼。需要注意的是,在本專題中,系統呼叫是以 C 式函式的形式提供給使用者的作業系統服務。一般來說,在很多場景下,程式需要監視它建立的稱為子程序的程序。wait 函式族就是提供這種功能的,waitpid 就是其中之一。

wait 系統呼叫有多種限制,為了覆蓋更高階的功能,需要利用 waitpid 函式。即,如果一個程序建立了多個子程序,而父程序需要監控某個特定的子程序,只有 waitpid 可以做到這一點。在下面的例子中,我們實現了一個名為 spawnChild 的函式,它可以建立一個新的子程序,並執行不同的程式。為了很好地演示這個例子,我們正在執行一個 top 程式(幾乎所有基於 Unix 的系統都有),這個程式一直執行到使用者終止它。一旦函式在父程序中返回,我們就儲存一個子程序的 ID,並將其傳遞給 waitpid 函式來監視狀態。

waitpid 需要三個引數,其中第一個引數是程序 PID 號(pid)。pid 可以有多個預先指定的值,並有不同的效果,但在本例中,我們只提 -1>0-1 值可以傳遞給監控任何先改變其狀態的子程序,它用來實現 wait 功能。>0 意味著該值應該是由 fork 函式返回的實際程序 ID,而這個 ID 又只用來監視特定的子程序。第二個引數的型別是 int 指標,我們應該宣告一個整數變數,將其地址傳遞給函式。而 waitpid 則會將子程序的狀態資訊儲存在給定的 int 變數中,然後可以使用預定義的巨集進行解碼。最後一個引數的型別是 int,除了預設的事件外,它還用來指定要監控的某些子程序事件。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.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);
}

在 C 語言中使用巨集來顯示子程序的等待狀態

需要注意的是,當 waitpid 函式被呼叫時,父程序是被暫停的,直到被監控的子程序改變狀態,它才會恢復執行。下一個例子顯示了 waitpid 呼叫時帶有 WUNTRACEDWCONTINUED 引數,這意味著父程序通過相應的訊號來監控子程序是否被停止或繼續。另外,我們還實現了 printWaitStatus 函式,可以呼叫它來列印檢索到的子程式狀態。注意,它是使用 <sys/wait.h> 頭中定義的 W*型別巨集,從 status 整數變數中提取編碼資訊。

由於不是所有的巨集在所有的平臺上都可以使用,所以有一些條件性的預處理程式定義,從而保證了函式的可移植性,無論如何都能編譯成功。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.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);
}
Author: 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

相關文章 - C Process