在Linux中从/proc获取PID列表

4
我正在制作一个程序,可以查看某些进程是否发生页面错误(page fault), 我的方法是获取所有进程的PID,并在每个单独的 /proc/[PID] 中查找 rssmaj_flt 等信息,检查总 maj_flt 是否有变化。
但为了获得所有正在运行进程的PID,我需要直接从我的C程序中获取它们,而不使用像 pstop等现有的Shell命令。
是否有人知道正在运行的PID数据存在于 /proc 或其他地方?或者是否有另一种方法来实现这一点,例如通过C程序中的系统调用函数获取?
3个回答

9
很遗憾,没有系统调用可以公开进程ID列表。在Linux中获取此信息的方法是通过虚拟文件系统/proc
如果您想要当前运行的进程PID列表,可以使用opendir()readdir()来打开/proc并遍历其中的文件/目录列表。然后,您可以检查文件名为数字的目录。检查之后,您可以打开/proc/<PID>/stat以获取所需的信息(特别是,您需要第12个字段majflt)。
这里是一个简单的工作示例(可能需要进行更多错误检查和调整):
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <ctype.h>

// Helper function to check if a struct dirent from /proc is a PID directory.
int is_pid_dir(const struct dirent *entry) {
    const char *p;

    for (p = entry->d_name; *p; p++) {
        if (!isdigit(*p))
            return 0;
    }

    return 1;
}

int main(void) {
    DIR *procdir;
    FILE *fp;
    struct dirent *entry;
    char path[256 + 5 + 5]; // d_name + /proc + /stat
    int pid;
    unsigned long maj_faults;

    // Open /proc directory.
    procdir = opendir("/proc");
    if (!procdir) {
        perror("opendir failed");
        return 1;
    }

    // Iterate through all files and directories of /proc.
    while ((entry = readdir(procdir))) {
        // Skip anything that is not a PID directory.
        if (!is_pid_dir(entry))
            continue;

        // Try to open /proc/<PID>/stat.
        snprintf(path, sizeof(path), "/proc/%s/stat", entry->d_name);
        fp = fopen(path, "r");

        if (!fp) {
            perror(path);
            continue;
        }

        // Get PID, process name and number of faults.
        fscanf(fp, "%d %s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %lu",
            &pid, &path, &maj_faults
        );

        // Pretty print.
        printf("%5d %-20s: %lu\n", pid, path, maj_faults);
        fclose(fp);
    }

    closedir(procdir);
    return 0;
}

示例输出:

    1 (systemd)           : 37
   35 (systemd-journal)   : 1
   66 (systemd-udevd)     : 2
   91 (dbus-daemon)       : 4
   95 (systemd-logind)    : 1
  113 (dhclient)          : 2
  143 (unattended-upgr)   : 10
  148 (containerd)        : 11
  151 (agetty)            : 1
  ...

3
完成后应该调用 closedir(procdir); 吗? - jpo38
1
@jpo38 确实,谢谢你指出这一点。 - Marco Bonelli
此外,进程名称在此被截断。可以使用readlink(请参见https://dev59.com/l2035IYBdhLWcg3wQtun#5525712)来读取/ proc / <pid> / exe以获取完整的可执行文件名称。 - jpo38

1
Linux提供了伪文件系统/proc来帮助用户获取进程信息,而不是提供系统调用。在/proc/[pid]目录中列出目录并解析类似于psinfo或cmdline的文件是获取进程信息的实用方法。
我不确定您想获取进程的哪些属性,但我建议您在命令行上键入“man proc”,以便您可以找出/proc/[pid]中的哪些文件包含您需要的信息。我猜测/proc/[pid]/stat包含您需要的信息。

0
你可以使用openproc来查询虚拟文件系统中可用的数据(请参见man 3 openproc)。需要安装procps库才能编译代码。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <proc/readproc.h>

// compile with:
// gcc environ.c -lprocps -o bin/environ
int main(){

  PROCTAB* proc = openproc(PROC_FILLSTAT);
  proc_t proc_info;
  memset(&proc_info, 0, sizeof(proc_info));
  while (readproc(proc, &proc_info) != NULL) {
    printf("%i,%i:\t %lu\n", proc_info.ppid, proc_info.tid, proc_info.maj_flt);
  }
  closeproc(proc);
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接