You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FreeBSD下如何用C语言通过父PID获取子进程?

在FreeBSD中通过父PID获取子进程的C语言实现方案

首先明确:FreeBSD没有提供直接通过父PID查询子进程的系统调用,pgrep -P <PID>的底层实现就是遍历系统中所有进程,检查每个进程的父PID是否匹配目标值——这是当前唯一可行且符合系统规范的方案,不用纠结“效率低”的问题,内核通过sysctl返回进程列表是批量操作,遍历的开销极小,完全能满足常规场景需求。

实现步骤(基于kinfo_proc,无需procfs)

核心是通过sysctl调用获取系统所有进程的kinfo_proc结构体,再遍历筛选出父PID匹配的进程:

  1. 调用sysctl获取进程列表
    使用sysctl的CTL_KERN + KERN_PROC + KERN_PROC_ALL参数,一次性获取系统中所有进程的信息。需要先调用一次sysctl获取所需内存大小,再分配内存后二次调用获取实际数据。

  2. 遍历筛选子进程
    遍历每个kinfo_proc结构体,检查kp_ppid字段是否等于目标父PID,匹配的进程即为目标子进程,提取其kp_pid即可。

示例代码

#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
#include <stdio.h>
#include <stdlib.h>

int get_children(pid_t parent_pid, pid_t **children, size_t *count) {
    int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t len = 0;
    struct kinfo_proc *proc_list = NULL;
    pid_t *child_list = NULL;
    size_t child_count = 0;

    // 第一次调用获取所需内存大小
    if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1) {
        perror("sysctl get len");
        return -1;
    }

    // 分配内存
    proc_list = malloc(len);
    if (proc_list == NULL) {
        perror("malloc proc_list");
        return -1;
    }

    // 第二次调用获取进程列表
    if (sysctl(mib, 4, proc_list, &len, NULL, 0) == -1) {
        perror("sysctl get proc_list");
        free(proc_list);
        return -1;
    }

    // 计算进程数量
    size_t proc_count = len / sizeof(struct kinfo_proc);

    // 遍历筛选子进程
    for (size_t i = 0; i < proc_count; i++) {
        if (proc_list[i].kp_ppid == parent_pid) {
            // 扩容子进程数组
            pid_t *tmp = realloc(child_list, (child_count + 1) * sizeof(pid_t));
            if (tmp == NULL) {
                perror("realloc child_list");
                free(proc_list);
                free(child_list);
                return -1;
            }
            child_list = tmp;
            child_list[child_count++] = proc_list[i].kp_pid;
        }
    }

    // 输出结果
    *children = child_list;
    *count = child_count;

    free(proc_list);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <parent_pid>\n", argv[0]);
        return 1;
    }

    pid_t parent_pid = atoi(argv[1]);
    pid_t *children = NULL;
    size_t count = 0;

    if (get_children(parent_pid, &children, &count) == -1) {
        return 1;
    }

    printf("Child processes of PID %d:\n", parent_pid);
    for (size_t i = 0; i < count; i++) {
        printf("%d\n", children[i]);
    }

    free(children);
    return 0;
}

补充说明

  • 该方案完全依赖FreeBSD原生的sysctl接口,无需挂载procfs,符合跨实例运行的需求。
  • 虽然是遍历所有进程,但sysctl返回的是内核维护的进程快照,遍历操作的CPU和内存开销都非常小,在常规服务器环境下几乎可以忽略。
  • pgrep工具的核心逻辑和上述代码一致,这是FreeBSD上实现该功能的标准方式。

内容的提问来源于stack exchange,提问作者AFreeChameleon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:57:21