当前位置:首页 > 技术 > 正文内容

Linux 系统下使用 waitpid 函数回收子进程

访客 技术 2026年10月26日 1

waitpid 函数是 Linux 系统中用于进程间通信和同步的一个重要函数,它允许父进程等待并获取子进程的终止状态。与 wait 函数类似,waitpid 提供了更精细的控制,允许指定等待哪个子进程以及以何种方式等待。

可以通过在 Linux 终端输入命令 man 2 waitpid 来查看 waitpid 函数的详细描述:


#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *wstatus, int options);
    

函数作用

waitpid 函数用于回收指定进程 ID 的子进程,并可以设置等待方式为阻塞或非阻塞。

参数详解

  • pid_t pid: 指定要等待的子进程的 ID。
    • < -1: 等待任何一个进程组 ID 等于 pid 绝对值的子进程。
    • -1: 等待任何一个子进程,等同于 wait() 函数。这是最常用的选项。
    • 0: 等待当前进程组内的任何一个子进程。
    • > 0: 等待指定进程 ID (pid) 的子进程。
  • int *wstatus: 一个指向整型变量的指针,用于存储子进程退出时的状态信息。这是一个传出参数。
    • 返回值 (成功时): 返回被回收的子进程的 ID。
    • 返回值 (失败时): 返回 -1,表示调用失败,或者所有子进程都已被回收。
  • int options: 设置等待方式。
    • 0: 阻塞等待,直到有子进程退出。
    • WNOHANG: 非阻塞等待,如果当前没有子进程退出,则立即返回。

返回值

  • > 0: 返回被回收子进程的 ID。
  • = 0: 当 options 设置为 WNOHANG 时,表示还有子进程存在但未退出。
  • -1: 表示发生错误,或者没有可回收的子进程。

状态宏

  • WIFEXITED(wstatus): 如果子进程正常退出(例如调用 exit() 或 _exit(),或者从 main 函数返回),则返回真。
  • WEXITSTATUS(wstatus): 返回子进程的退出状态码。这仅在 WIFEXITED 返回真时才有效。
  • WIFSIGNALED(wstatus): 如果子进程被信号终止,则返回真。
  • WTERMSIG(wstatus): 返回导致子进程终止的信号编号。这仅在 WIFSIGNALED 返回真时才有效。

示例代码

下面的代码演示了父进程如何创建多个子进程,并使用 waitpid 函数以非阻塞方式回收它们。


#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>

// 使用 std 命名空间
using std::cout;
using std::endl;

namespace waitpid_example {
    void run_test() {
        pid_t child_pid;
        const int num_children = 5;

        // 父进程创建 num_children 个子进程
        for (int i = 0; i < num_children; ++i) {
            child_pid = fork();
            if (child_pid == 0) {
                // 子进程逻辑
                cout << "Child process (PID: " << getpid() <<) started." << endl;
                sleep(2); // 模拟子进程工作
                cout << "Child process (PID: " << getpid() <<) exiting." << endl;
                exit(i + 1); // 以不同的状态码退出
            } else if (child_pid < 0) {
                perror("fork failed");
                return; // 退出函数
            }
        }

        // 父进程逻辑
        if (child_pid > 0) {
            cout << "Parent process (PID: " << getpid() <<) waiting for children..." << endl;
            int child_status;
            int exited_children = 0;

            // 使用非阻塞方式等待子进程
            while (exited_children < num_children) {
                pid_t terminated_pid = waitpid(-1, &child_status, WNOHANG);

                if (terminated_pid == -1) {
                    // 发生错误或所有子进程已回收
                    perror("waitpid error");
                    break;
                } else if (terminated_pid == 0) {
                    // 没有子进程退出,继续循环
                    // cout << "Parent: No child has exited yet." << endl;
                    sleep(1); // 短暂休眠,避免 CPU 占用过高
                } else {
                    // 某个子进程已退出
                    exited_children++;
                    cout << "Parent: Child process (PID: " << terminated_pid <<) terminated." << endl;

                    if (WIFEXITED(child_status)) {
                        cout << "  Normal exit with status: " << WEXITSTATUS(child_status) << endl;
                    } else if (WIFSIGNALED(child_status)) {
                        cout << "  Killed by signal: " << WTERMSIG(child_status) << endl;
                    }
                }
            }
            cout << "Parent process finished waiting." << endl;
        }
        // else if (child_pid == 0) {
        //     // 子进程逻辑已在上面 fork 循环中处理
        // }
    }
}

int main() {
    waitpid_example::run_test();
    return 0;
}
    

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。