从C和C ++的父进程获取子进程列表(跨平台,无fork())

问题描述 投票:0回答:1

[如何在不使用fork()的情况下,以跨平台的方式从给定的父进程ID中获取子进程ID的列表,这种跨平台方式在C和C ++中?我自己提供了一个答案,下面涵盖了使用C ++的Win32,macOS,Linux,FreeBSD和Darwin。

随意将我的代码转换为C解决方案,(以及根据需要提供的本机api或posix,我需要澄清这一点真是可惜,大声笑),或使用其他API或方法提供自己的解决方案,但无需使用fork ()。添加对更多平台的支持显然也很受欢迎。

例如:其他BSD,Solaris,移动平台等

c++ c cross-platform desktop pid
1个回答
0
投票

Win32

#include "childpids.h"
#include <windows.h>
#include <tlhelp32.h>

using std::string;
using std::to_string;

string pids_from_ppid_helper(process_t ppid) {
  string pids;
  HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  PROCESSENTRY32 pe = { 0 };
  pe.dwSize = sizeof(PROCESSENTRY32);
  if (Process32First(hp, &pe)) {
    do {
      if (pe.th32ParentProcessID == ppid) {
        pids += to_string(pe.th32ProcessID) + "|";
      }
    } while (Process32Next(hp, &pe));
  }
  if (pids.back() == '|')
    pids.pop_back();
  pids += "\0";
  CloseHandle(hp);
  return pids;
}

macOS和达尔文

#include "childpids.h"
#include <sys/proc_info.h>
#include <libproc.h>
#include <cstring>

using std::string;
using std::to_string;

static inline process_t ppid_from_pid(process_t pid) {
  process_t ppid;
  proc_bsdinfo proc_info;
  if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc_info, sizeof(proc_info)) > 0) {
    ppid = proc_info.pbi_ppid;
  }
  return ppid;
}

string pids_from_ppid_helper(process_t ppid) {
  string pids;
  int cntp = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
  process_t proc_info[cntp];
  memset(&proc_info, 0, sizeof(proc_info));
  proc_listpids(PROC_ALL_PIDS, 0, proc_info, sizeof(proc_info));
  for (unsigned i = 0; i < cntp; i++) {
    if (proc_info[i] == 0) { continue; }
    if (ppid_from_pid(proc_info[i]) == ppid) {
      pids += to_string(proc_info[i]) + "|";
    }
  }
  if (pids.back() == '|')
    pids.pop_back();
  pids += "\0";
  return pids;
}

Linux(链接:-lprocps)

// Note: Ubuntu/Debian need to install libprocps-dev for the development headers.
// All major Linux distros *should* have the actual library installed by default.

#include "childpids.h"
#include <proc/readproc.h>
#include <cstring>

using std::string;
using std::to_string;

string pids_from_ppid_helper(process_t ppid) {
  string pids;
  proc_t proc_info;
  memset(&proc_info, 0, sizeof(proc_info));
  PROCTAB *proc = openproc(PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS);
  while (readproc(proc, &proc_info) != 0) {
    if (proc_info.ppid == ppid) {
      pids += to_string(proc_info.tid) + "|";
    }
  }
  if (pids.back() == '|')
    pids.pop_back();
  pids += "\0";
  return pids;
}

FreeBSD(链接:-lutil -lc)

// Note: libutil.h is specific to the FreeBSD BSD distro.
// For more BSD support, call sysctl() function directly.

#include "childpids.h"
#include <sys/types.h>
#include <sys/user.h>
#include <libutil.h>

using std::string;
using std::to_string;

string pids_from_ppid_helper(process_t ppid) {
  string pids; int cntp;
  struct kinfo_proc *proc_info = kinfo_getallproc(&cntp);
  if (proc_info) {
    for (unsigned i = 0; i < cntp; i++) {
      if (proc_info[i].ki_ppid == ppid) {
        pids += to_string(proc_info[i].ki_tid) + "|";
      }
    }
  }
  if (pids.back() == '|')
    pids.pop_back();
  pids += "\0";
  return pids;
}

childpids.h

#include <string>

// pid_t is signed, but only returns negative for fork() errors
// we are not using posix fork() anywhere, so this should be ok
typedef unsigned long process_t;

std::string pids_from_ppid_helper(process_t ppid);

childpids.cpp

#include "childpids.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <string>

using std::string;

static inline std::vector<string> string_split(string str, char delimiter) {
  std::vector<string> vec;
  std::stringstream sstr(str);
  string tmp;
  while (std::getline(sstr, tmp, delimiter))
    vec.push_back(tmp);
  return vec;
}

void pids_from_ppid(process_t ppid) {
  string pids = pids_from_ppid_helper(ppid);
  std::vector<string> pidVec = string_split(pids, '|');
  for (const string &pid : pidVec) {
    if (pid != "" && pid != "0") {
      pids_from_ppid(stoul(pid, nullptr, 10)); // recursive
      std::cout << pid << std::endl; // show children first
    }
  }
}

int main(int argc, char *argv[]) {
  string arg = (argc == 2) ? argv[1] : "0";
  pids_from_ppid(stoul(arg, nullptr, 10));
  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.