C++ 为什么if(fork()==0){getpid()}和一个popen()进程返回相同的进程id?
我想知道,据我所知,fork()中的getpid()应该是一个与popen()生成的进程不同的进程,为什么这两个进程id匹配 我被告知,我的代码之所以能工作,是因为我解释的可能是基于Ubuntu的发行版的bug,比如Xubuntu、Lubuntu和KDE neon(这是我迄今为止测试过的发行版)。您可以从此处轻松编译和测试代码:如果不信任该链接,请忽略该链接中可用的x64二进制文件。Arch、RedHat等。如果这对他们不起作用,特别欢迎测试人员提供反馈 这里有一个更简单的方法来演示这个问题:C++ 为什么if(fork()==0){getpid()}和一个popen()进程返回相同的进程id?,c++,linux,x11,xlib,C++,Linux,X11,Xlib,我想知道,据我所知,fork()中的getpid()应该是一个与popen()生成的进程不同的进程,为什么这两个进程id匹配 我被告知,我的代码之所以能工作,是因为我解释的可能是基于Ubuntu的发行版的bug,比如Xubuntu、Lubuntu和KDE neon(这是我迄今为止测试过的发行版)。您可以从此处轻松编译和测试代码:如果不信任该链接,请忽略该链接中可用的x64二进制文件。Arch、RedHat等。如果这对他们不起作用,特别欢迎测试人员提供反馈 这里有一个更简单的方法来演示这个问题:
// USAGE: xprocesstest [command]
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <unistd.h>
#include <thread>
#include <chrono>
#include <iostream>
#include <string>
using std::string;
static inline Window XGetActiveWindow(Display *display) {
unsigned long window;
unsigned char *prop;
Atom actual_type, filter_atom;
int actual_format, status;
unsigned long nitems, bytes_after;
int screen = XDefaultScreen(display);
window = RootWindow(display, screen);
filter_atom = XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
status = XGetWindowProperty(display, window, filter_atom, 0, 1000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
unsigned long long_property = prop[0] + (prop[1] << 8) + (prop[2] << 16) + (prop[3] << 24);
XFree(prop);
return (Window)long_property;
}
static inline pid_t XGetActiveProcessId(Display *display) {
unsigned long window = XGetActiveWindow(display);
unsigned char *prop;
Atom actual_type, filter_atom;
int actual_format, status;
unsigned long nitems, bytes_after;
filter_atom = XInternAtom(display, "_NET_WM_PID", True);
status = XGetWindowProperty(display, window, filter_atom, 0, 1000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
unsigned long long_property = prop[0] + (prop[1] << 8) + (prop[2] << 16) + (prop[3] << 24);
XFree(prop);
return (pid_t)(long_property - 1);
}
int main(int argc, const char **argv) {
if (argc == 2) {
char *buffer = NULL;
size_t buffer_size = 0;
string str_buffer;
FILE *file = popen(argv[1], "r");
if (fork() == 0) {
Display *display = XOpenDisplay(NULL);
Window window;
unsigned i = 0;
while (i < 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (XGetActiveProcessId(display) == getpid()) {
window = XGetActiveWindow(display);
break;
}
i++;
}
if (window == XGetActiveWindow(display))
std::cout << "process id's match!" << std::endl;
else std::cout << "process id's don't match!" << std::endl;
XCloseDisplay(display);
exit(0);
}
while (getline(&buffer, &buffer_size, file) != -1)
str_buffer += buffer;
std::cout << str_buffer;
free(buffer);
pclose(file);
}
}
运行时使用:
cd "${0%/*}"
./xprocesstest "kdialog --getopenfilename"
您可以将引号中的命令替换为设置_NET_WM_PID atom的任何可执行文件。@OtherGuy在其评论中解释了答案:
“您是否知道,由于您的-1,您实际上正在检查这两个进程是否具有顺序PID?这在Linux上并不奇怪。发行版之间的差异将取决于sh是否优化了用于运行命令的额外fork”
静态内联pid\t XGetActiveProcessId(显示*显示){
无符号长窗口=XGetActiveWindow(显示);
无符号字符*prop;
原子实际_类型,过滤器_原子;
int实际_格式、状态;
无符号长nitems,后面为字节;
filter\u atom=XInternAtom(显示“\u NET\u WM\u PID”,真);
状态=XGetWindowProperty(显示、窗口、筛选器、原子、0、1000、False、AnyPropertyType、&actual类型、&actual格式、&nitems、&bytes之后、&prop);
无符号long_属性=prop[0]+(prop[1]这是真的吗?不可能删除一半的代码来复制它?Xubuntu、Lubuntu和Ubuntu是同一个发行版,具有不同的桌面环境。是的,我会处理它,对此很抱歉。尽管值得注意的是,不同的桌面环境可能意味着不同的默认窗口管理器和软件包,我不确定我认为问题正如我所描述的那样。我在openSUSE或Archlinux上使用g++-Wall-Wextra-pedantic-std=gnu++11-Ofast-lX11-o bin/xprocesstest-xprocesstest.cpp构建时没有任何问题,并且在kdialog
和zenity
两种情况下都成功运行t“进程id不匹配!”
根据链接,这并不意外。您是否知道,由于您的-1
,您实际上正在检查这两个进程是否具有顺序PID?这在Linux上并不奇怪。发行版之间的差异将取决于sh
是否优化了它用于运行命令的额外分叉
cd "${0%/*}"
./xprocesstest "kdialog --getopenfilename"
static inline pid_t XGetActiveProcessId(Display *display) {
unsigned long window = XGetActiveWindow(display);
unsigned char *prop;
Atom actual_type, filter_atom;
int actual_format, status;
unsigned long nitems, bytes_after;
filter_atom = XInternAtom(display, "_NET_WM_PID", True);
status = XGetWindowProperty(display, window, filter_atom, 0, 1000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
unsigned long long_property = prop[0] + (prop[1] << 8) + (prop[2] << 16) + (prop[3] << 24);
XFree(prop);
return (pid_t)(long_property - 1);
}
#include <proc/readproc.h>
#include <cstring>
static inline pid_t GetParentPidFromPid(pid_t pid) {
proc_t proc_info; pid_t ppid;
memset(&proc_info, 0, sizeof(proc_info));
PROCTAB *pt_ptr = openproc(PROC_FILLSTATUS | PROC_PID, &pid);
if(readproc(pt_ptr, &proc_info) != 0) {
ppid = proc_info.ppid;
string cmd = proc_info.cmd;
if (cmd == "sh")
ppid = GetParentPidFromPid(ppid);
} else ppid = 0;
closeproc(pt_ptr);
return ppid;
}
while (i < 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (GetParentPidFromPid(XGetActiveProcessId(display)) == GetParentPidFromPid(getpid()) ||
GetParentPidFromPid(GetParentPidFromPid(XGetActiveProcessId(display))) == GetParentPidFromPid(getppid())) {
window = XGetActiveWindow(display);
break;
}
i++;
}