监视进程是否已在 C 中终止
Monitor if a process has terminated in C
简介
我正在用 C 编写一个监控程序,它执行 fork()
和 exec()
循环。但是我需要检查 child 进程是否已经终止而不阻塞主进程,即监控程序。像这样:
主要流程
pid_t child_pid = fork();
if (child_pid == 0)
exec(bar);
while (1) {
if (the child process has finished)
foo();
else
bar();
}
我试过的
考虑到我有 child pid 的事实,我尝试了以下操作:
正在发送 kill
调用 signal 0
并检查 errno
:
if (kill(child_pid, 0) == -1 || errno == ESRCH)
,我认为这不是跟踪 child 进程状态的好方法,因为它在竞争条件下并不安全。而且它没有用,或者至少看起来是这样。
用stat(2)
检查是否存在proc/child_pid
。在这种情况下,上述所有否定参数都是正确的,而且这种方法速度较慢。
waitpid(2)
。不幸的是它阻塞了主进程。
问题
请问还有其他途径获取此类信息吗?或者我可能遗漏了一些我已经尝试过的解决方案?
如果您将 WNOHANG
传递给 waitpid
,它应该不会阻塞。
if(waitpid(child_pid, &status, WNOHANG) != 0) {
// child process has finished
foo();
} else {
// child process still running
bar();
}
当进程终止时,您可以设置父进程来获取和处理 SIGCHLD
信号,参见 signal(7); the signal handler can only call async-signal-safe functions, or set a volatile sigatomic_t
flag tested outside of the handler (e.g. in your main event loop around poll(2)...), or write(2) to some file descriptor (e.g. a pipe or some eventfd(2)). As 您也可以使用 Linux-specific signalfd
.
然后你可以使用一些等待功能,例如waitpid(2) (perhaps with WNOHANG
if you don't want to block) or wait4(2)等待进程并获取其状态等
另请阅读 Advanced Linux Programming 了解更多信息。它有几个章节讨论这些问题。
如果您希望您的进程不阻塞,或者您可能有其他文件描述符需要检查,如果您正在为 Linux 编写,您应该考虑 signalfd() 系统调用.
此系统调用返回一个特殊的文件描述符,您可以在 select()
、poll()
和 epoll()
系统调用中使用它。设置正确,子进程退出会导致内核使特殊文件描述符可读。从特殊文件描述符中读取会为您提供一个填充结构,其中包含有关子进程退出状态的信息。
Basile Starynkevitch 的回答涵盖了大多数常见情况。
如果您有更多不寻常的情况,有时使用管道会很有用。在创建 child 进程之前,使用 pipe
系统调用创建一个管道。创建 child 进程后,关闭 parent 进程中管道的写入端。从管道读取会阻塞,直到 child 终止。
这与 waitpid
在以下方面有所不同:
- 从管道读取将等待 child 及其所有 children 终止(除非其中一些在此之前关闭文件描述符)。
- 可能有多个进程从同一个文件描述符读取,导致所有进程都等待同一个(或多个)进程终止。
- 您不限于等待 child 终止。使用此方法,您还可以等待 parent 或兄弟终止。
- 通过在 exec 上使用 close,您可以等待进程终止或成功执行
execve
系统调用。
- 您可以在管道上使用
select
或 poll
系统调用以及其他文件描述符。
简介
我正在用 C 编写一个监控程序,它执行 fork()
和 exec()
循环。但是我需要检查 child 进程是否已经终止而不阻塞主进程,即监控程序。像这样:
主要流程
pid_t child_pid = fork();
if (child_pid == 0)
exec(bar);
while (1) {
if (the child process has finished)
foo();
else
bar();
}
我试过的
考虑到我有 child pid 的事实,我尝试了以下操作:
正在发送
kill
调用signal 0
并检查errno
:if (kill(child_pid, 0) == -1 || errno == ESRCH)
,我认为这不是跟踪 child 进程状态的好方法,因为它在竞争条件下并不安全。而且它没有用,或者至少看起来是这样。用
stat(2)
检查是否存在proc/child_pid
。在这种情况下,上述所有否定参数都是正确的,而且这种方法速度较慢。waitpid(2)
。不幸的是它阻塞了主进程。
问题
请问还有其他途径获取此类信息吗?或者我可能遗漏了一些我已经尝试过的解决方案?
如果您将 WNOHANG
传递给 waitpid
,它应该不会阻塞。
if(waitpid(child_pid, &status, WNOHANG) != 0) {
// child process has finished
foo();
} else {
// child process still running
bar();
}
当进程终止时,您可以设置父进程来获取和处理 SIGCHLD
信号,参见 signal(7); the signal handler can only call async-signal-safe functions, or set a volatile sigatomic_t
flag tested outside of the handler (e.g. in your main event loop around poll(2)...), or write(2) to some file descriptor (e.g. a pipe or some eventfd(2)). As signalfd
.
然后你可以使用一些等待功能,例如waitpid(2) (perhaps with WNOHANG
if you don't want to block) or wait4(2)等待进程并获取其状态等
另请阅读 Advanced Linux Programming 了解更多信息。它有几个章节讨论这些问题。
如果您希望您的进程不阻塞,或者您可能有其他文件描述符需要检查,如果您正在为 Linux 编写,您应该考虑 signalfd() 系统调用.
此系统调用返回一个特殊的文件描述符,您可以在 select()
、poll()
和 epoll()
系统调用中使用它。设置正确,子进程退出会导致内核使特殊文件描述符可读。从特殊文件描述符中读取会为您提供一个填充结构,其中包含有关子进程退出状态的信息。
Basile Starynkevitch 的回答涵盖了大多数常见情况。
如果您有更多不寻常的情况,有时使用管道会很有用。在创建 child 进程之前,使用 pipe
系统调用创建一个管道。创建 child 进程后,关闭 parent 进程中管道的写入端。从管道读取会阻塞,直到 child 终止。
这与 waitpid
在以下方面有所不同:
- 从管道读取将等待 child 及其所有 children 终止(除非其中一些在此之前关闭文件描述符)。
- 可能有多个进程从同一个文件描述符读取,导致所有进程都等待同一个(或多个)进程终止。
- 您不限于等待 child 终止。使用此方法,您还可以等待 parent 或兄弟终止。
- 通过在 exec 上使用 close,您可以等待进程终止或成功执行
execve
系统调用。 - 您可以在管道上使用
select
或poll
系统调用以及其他文件描述符。