如何在C和C ++中以跨平台方式从给定的父进程ID获取子进程ID的列表,而不使用命令行?我在下面提供了一个答案,其中涉及使用C ++的Win32,macOS,Linux,FreeBSD和Darwin。
可以随意将我的代码转换为C解决方案(以及根据需要提供的本机api或posix),或使用其他API或方法提供自己的解决方案,但无需使用popen()或system()之类的东西。添加对更多平台的支持显然也很受欢迎。
例如:其他BSD,Solaris,移动平台等。
答案 0 :(得分:4)
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和Darwin
#include <algorithm>
#include <vector>
#include <cstring>
#include "childpids.h"
#include <sys/proc_info.h>
#include <libproc.h>
using std::string;
using std::vector;
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);
vector<pid_t> proc_info(cntp);
std::fill(proc_info.begin(), proc_info.end(), 0);
proc_listpids(PROC_ALL_PIDS, 0, &proc_info[0], sizeof(pid_t) * cntp);
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 <cstring>
#include "childpids.h"
#include <proc/readproc.h>
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.tgid) + "|";
}
}
if (pids.back() == '|')
pids.pop_back();
pids += "\0";
closeproc(proc);
return pids;
}
FreeBSD(链接:-lutil -lc)
// Note: libutil.h is specific to the FreeBSD BSD distro.
// For more BSD support, call sysctl() function directly.
#include <cstdlib>
#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_pid) + "|";
}
}
}
if (pids.back() == '|')
pids.pop_back();
pids += "\0";
free(proc_info);
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 <iostream>
#include <sstream>
#include <vector>
#include <string>
#include "childpids.h"
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;
}