监视进程是否已在C中终止

0x4*_*450 7 c monitoring fork process

介绍

我正在用C编写一个监控程序,它执行fork()exec()循环.但是,我需要在不阻塞主进程(即监视程序)的情况下检查子进程是否已终止.像这样的东西:

主要过程

pid_t child_pid = fork();
if (child_pid == 0)
    exec(bar);

while (1) {
    if (the child process has finished)
        foo();
    else
        bar();
}
Run Code Online (Sandbox Code Playgroud)

我试过了什么

考虑到我有孩子pid的事实,我尝试了以下方法:

  • 发送kill电话signal 0并进行检查errno:

    if (kill(child_pid, 0) == -1 || errno == ESRCH)我认为这不是跟踪儿童过程状态的好方法,因为它不受种族条件的影响.此外它没有用,或者至少看起来如此.

  • 检查stat(2)是否proc/child_pid存在.在这种情况下,所有上述否定参数都是正确的,并且此方法较慢.

  • waitpid(2).不幸的是,它阻碍了主要过程.

这个问题

有没有其他方法可以获得这种信息?或者也许我错过了我已经尝试过的解决方案?

Eri*_*ouf 13

如果你传递WNOHANGwaitpid它不应该阻止.

if(waitpid(child_pid, &status, WNOHANG) != 0) {
    // child process has finished
    foo();
} else {
    // child process still running
    bar();
}
Run Code Online (Sandbox Code Playgroud)


Bas*_*tch 11

当一个进程终止时,你可以设置父进程来获取和处理一个SIGCHLD信号,参见signal(7) ; 信号处理程序只能调用异步信号安全函数,或设置volatile sigatomic_t在处理程序外测试的标志(例如在poll(2)周围的主事件循环中...),或者将(2)写入某个文件描述符(例如管道或某个eventfd(2)).正如Bruce Ediger所说,你也可以使用特定于Linux的signalfd.

然后你可以使用一些等待函数,例如waitpid(2)(WNOHANG如果你不想阻止)或者wait4(2)等待进程并获得它的状态等.

另请参阅高级Linux编程.它有几个关于这些问题的章节.


Bru*_*ger 7

如果你希望你的过程中不堵塞,或者你已经有了其他文件描述符来检查了,你应该考虑signalfd()如果你正在写的Linux系统调用.

这个系统调用给回一个特殊的文件描述符,你可以在使用select(),poll()并且epoll()系统调用.正确设置,子进程退出会导致内核生成特殊文件描述符readabl.从特殊文件描述符中读取会为您提供一个填充结构,其中包含有关子进程退出状态的信息.


kas*_*erd 5

Basile Starynkevitch的答案涵盖了最常见的情况.

如果您有更多不寻常的情况,有时使用管道是有用的.在创建子进程之前,使用pipe系统调用创建管道.创建子进程后,关闭父进程中管道的写入结束.从管道读取将阻止直到孩子终止.

这与waitpid以下方式不同:

  • 从管道读取将等待子节点及其所有子节点终止(除非其中一些子节点在此之前关闭文件描述符).
  • 可以从同一文件描述符中读取多个进程,导致所有进程等待相同的进程(或进程)终止.
  • 您不限于等待孩子终止.使用此方法,您还可以等待父级或兄弟级别终止.
  • 通过使用close on exec,您可以等待进程终止或成功执行execve系统调用.
  • 您可以在管道上使用selectpoll系统调用以及其他文件描述符.