Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么if(fork()==0){getpid()}和一个popen()进程返回相同的进程id?_C++_Linux_X11_Xlib - Fatal编程技术网

C++ 为什么if(fork()==0){getpid()}和一个popen()进程返回相同的进程id?

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等。如果这对他们不起作用,特别欢迎测试人员提供反馈 这里有一个更简单的方法来演示这个问题:

我想知道,据我所知,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++;
  }