FreeBSD下如何用C语言通过父PID获取子进程?
在FreeBSD中通过父PID获取子进程的C语言实现方案
首先明确:FreeBSD没有提供直接通过父PID查询子进程的系统调用,pgrep -P <PID>的底层实现就是遍历系统中所有进程,检查每个进程的父PID是否匹配目标值——这是当前唯一可行且符合系统规范的方案,不用纠结“效率低”的问题,内核通过sysctl返回进程列表是批量操作,遍历的开销极小,完全能满足常规场景需求。
实现步骤(基于kinfo_proc,无需procfs)
核心是通过sysctl调用获取系统所有进程的kinfo_proc结构体,再遍历筛选出父PID匹配的进程:
调用sysctl获取进程列表
使用sysctl的CTL_KERN+KERN_PROC+KERN_PROC_ALL参数,一次性获取系统中所有进程的信息。需要先调用一次sysctl获取所需内存大小,再分配内存后二次调用获取实际数据。遍历筛选子进程
遍历每个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
相关产品推荐
相关产品推荐

