【发布时间】:2019-11-09 23:52:53
【问题描述】:
据我所知,当 fork() 中的 getpid() 与 popen() 生成的进程不同时,我想知道为什么这两个进程 id 匹配。
我被告知我的代码只能工作,因为我解释可能是基于 Ubuntu 的发行版的错误,例如 Xubuntu、Lubuntu 和 KDE neon(这是我迄今为止测试过的发行版)。您可以从此处轻松编译和测试代码:https://github.com/time-killer-games/XTransientFor 如果您不信任,请忽略该链接中可用的 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%/*}"
g++ -c -std=c++17 "xprocesstest.cpp" -fPIC -m64
g++ "xprocesstest.o" -o "xprocesstest" -fPIC -lX11
运行:
cd "${0%/*}"
./xprocesstest "kdialog --getopenfilename"
您可以将引号中的命令替换为设置 _NET_WM_PID 原子的任何可执行文件。
【问题讨论】:
-
这真的是minimal reproducible example吗?不可以去掉一半的代码来重现吗? Xubuntu、Lubuntu 和 Ubuntu 是具有不同桌面环境的相同发行版。
-
不错,我会处理的,对此感到抱歉。
-
虽然值得注意的是不同的桌面环境可能意味着不同的默认窗口管理器和包,但我不确定这是否有任何区别,这就是我发布该内容的原因。
-
我认为问题如Is it possible to get active window & executable names in X11/Xlib? 所述。我在 openSUSE 或 Archlinux 上使用
g++ -Wall -Wextra -pedantic -std=gnu++11 -Ofast -lX11 -o bin/xprocesstest xprocesstest.cpp构建没有问题,并且使用kdialog和zenity成功运行。在这两种情况下,我都会得到"process id's don't match!",根据链接,这并不意外。 -
您是否知道,由于您的
- 1,您实际上正在检查两个进程是否具有sequential pids?这在 Linux 上并不奇怪。发行版之间的差异将取决于sh是否优化了它用于运行命令的额外分叉