【问题标题】:Getting list of PIDs from /proc in Linux在 Linux 中从 /proc 获取 PID 列表
【发布时间】:2020-12-01 22:51:17
【问题描述】:

我正在制作一个程序,可以查看某些进程中是否发生页面错误, 我的方法是获取所有进程的 PID,并通过在每个 /proc/[PID] 中查找来查看 rssmaj_flt 等,检查 maj_flt 的总数是否有变化。

但为了获取所有正在运行的进程的 PID,我需要直接从我的 C 程序中获取它们,而无需使用现有的 shell 命令,如 pstop 等。

有谁知道/proc 或其他地方运行的PID 数据在哪里?或者如果有其他方法可以做到这一点,比如通过我的 C 程序中的系统调用函数来获取它?

【问题讨论】:

    标签: c linux pid procfs


    【解决方案1】:

    您可以使用openproc 查询虚拟/proc 文件系统中的可用数据(请参阅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);
    }
    
    

    【讨论】:

      【解决方案2】:

      不幸的是,没有公开 PID 列表的系统调用。您应该在 Linux 中获取这些信息的方式是通过 /proc 虚拟文件系统。

      如果您想要当前正在运行的进程的 PID 列表,您可以使用 opendir()readdir() 打开 /proc 并遍历其中的文件/文件夹列表。然后您可以检查文件名是数字的文件夹。核对后直接打开/proc/&lt;PID&gt;/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 folder.
      int is_pid_folder(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 folders of /proc.
          while ((entry = readdir(procdir))) {
              // Skip anything that is not a PID folder.
              if (!is_pid_folder(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
        ...
      

      【讨论】:

      • 完成后不应该调用closedir(procdir);吗?
      • @jpo38 确实,感谢您指出这一点。
      • 另外,进程名称在这里被截断。人们可能会等待使用 readlink 读取 /proc//exe(参见 stackoverflow.com/a/5525712/3336423)以获得完整的可执行文件名。
      【解决方案3】:

      Linux 在 /proc 中提供伪文件系统来帮助用户获取进程信息,而不是提供系统调用。在 /proc/[pid] 中列出目录并解析 psinfo 或 cmdline 等文件是获取进程信息的实用方法。

      我不确定您想要获取哪些进程属性,但我建议您在命令行中键入“man proc”,以便您可以确定 /proc/[pid] 中的哪些文件包含信息你需要。我猜 /proc/[pid]/stat 包含您需要的信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-24
        • 2014-03-17
        • 1970-01-01
        • 2010-12-19
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多