如何等待退出非子进程

时间:2009-07-21 07:21:00

标签: c linux process wait

对于子进程,wait()waitpid()函数可用于暂停当前进程的执行,直到子进程退出。但是此功能不能用于非子进程。

是否有其他功能可以等待退出任何进程?

9 个答案:

答案 0 :(得分:26)

没有任何东西等同于wait()。通常的做法是使用kill(pid, 0)进行投票,并查找errno的返回值-1和ESRCH,以表明该过程已消失。

答案 1 :(得分:13)

在BSD和OS X上,你可以使用带有EVFILT_PROC + NOTE_EXIT的kqueue来做到这一点。不需要投票。不幸的是,没有Linux等价物。

答案 2 :(得分:9)

到目前为止,我已经在Linux上找到了三种方法:

  • 轮询:您经常检查是否存在流程,使用kill或测试是否存在/proc/$pid,与大多数其他答案一样
  • 使用ptrace系统调用作为调试程序附加到流程,以便在退出时收到通知,如a3nm's answer
  • 使用netlink接口来监听PROC_EVENT_EXIT消息 - 这样每次进程退出时内核都会告诉您的程序,而您只是等待正确的进程ID。我之前只看到过in one place on the internet

无耻的插件:我正在开发一个program(当然是开放源代码; GPLv2),它可以完成三个中的任何一个。

答案 3 :(得分:5)

您还可以创建套接字或FIFO并读取它们。 FIFO特别简单:将您孩子的标准输出连接到FIFO并读取。读取将阻止,直到子进程退出(出于任何原因)或直到它发出一些数据。因此,您需要一个小循环来丢弃不需要的文本数据。

如果您有权访问孩子的来源,请在启动时打开FIFO进行写入,然后将其忘记。当孩子终止并且等待的“父”进程将被唤醒时,操作系统将清除打开的文件描述符。

现在这可能是一个你没有开始或拥有的过程。在这种情况下,您可以使用启动实际二进制文件的脚本替换二进制可执行文件,但也可以添加监视,如上所述。

答案 4 :(得分:3)

您可以使用ptrace(2)附加到流程。从shell开始,strace -p PID >/dev/null 2>&1似乎有效。这可以避免忙碌等待,但它会减慢跟踪过程的速度,并且不会对所有进程起作用(只有你的进程,这比只有子进程好一点)。

答案 5 :(得分:2)

没有我知道。除了混乱的解决方案,如果你可以改变你想要等待的程序,你可以使用信号量。

库函数是sem_open(3)sem_init(3), sem_wait(3), ...

sem_wait(3)执行等待,所以你不必像在混乱的解决方案中那样忙着等待。当然,使用信号量会使你的程序变得更复杂,而且可能不值得麻烦。

答案 6 :(得分:1)

也许有可能等待/ proc / [pid]或/ proc / [pid] / [something]消失?

有poll()和其他文件事件等待函数,也许这可能有帮助吗?

答案 7 :(得分:1)

这是一种无需轮询即可等待linux中任何进程(不一定是子进程)退出(或被杀死)的方法:

使用inotify等待删除/ proc'pid'会是一个完美的解决方案,但是不幸的是inotify不适用于/ proc之类的伪文件系统。 但是,我们可以将其与进程的可执行文件一起使用。 尽管该过程仍然存在,但此文件保持打开状态。 因此,我们可以将inotify与IN_CLOSE_NOWRITE配合使用,直到文件关闭为止。 当然,可以出于其他原因(例如,如果另一个进程具有相同的可执行文件退出)而关闭它,因此我们必须通过其他方式过滤这些事件。

我们可以使用kill(pid,0),但是不能保证它仍然是相同的过程。如果我们真的对此感到偏执,我们可以做其他事情。

这是一种应该避免pid重用问题的100%安全的方法:我们打开伪目录/ proc /'pid',并保持打开状态直到完成。如果同时使用相同的pid创建新进程,则我们持有的目录文件描述符仍将引用原始进程(如果旧进程不存在,则将变为无效),但绝不会使用重用的pid。然后我们可以通过检查例如openat()目录中是否存在“ cmdline”文件来检查原始进程是否仍然存在。当进程退出或被杀死时,这些伪文件也不再存在,因此openat()将失败。

下面是示例代码:

// return -1 on error, or 0 if everything went well
int wait_for_pid(int pid)
{
    char path[32];
    int in_fd = inotify_init();
    sprintf(path, "/proc/%i/exe", pid);
    if (inotify_add_watch(in_fd, path, IN_CLOSE_NOWRITE) < 0) {
        close(in_fd);
        return -1;
    }
    sprintf(path, "/proc/%i", pid);
    int dir_fd = open(path, 0);
    if (dir_fd < 0) {
        close(in_fd);
        return -1;
    }

    int res = 0;
    while (1) {
        struct inotify_event event;
        if (read(in_fd, &event, sizeof(event)) < 0) {
            res = -1;
            break;
        }
        int f = openat(dir_fd, "fd", 0);
        if (f < 0) break;
        close(f);
    }

    close(dir_fd);
    close(in_fd);
    return res;
}

答案 8 :(得分:0)

从linux内核5.3开始,有一个pidfd_open系统调用,该调用为给定的pid创建一个fd,当pid退出时可以对其进行轮询以获得通知。