如何等待非子进程退出
对于子进程,wait()
和 waitpid()
函数可用于暂停当前进程的执行,直到子进程退出。 但该函数不能用于非子进程。
是否还有另一个函数可以等待任何进程的退出?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
对于子进程,wait()
和 waitpid()
函数可用于暂停当前进程的执行,直到子进程退出。 但该函数不能用于非子进程。
是否还有另一个函数可以等待任何进程的退出?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(14)
没有与
wait()
等效的东西。 通常的做法是使用kill(pid, 0)
进行轮询,并查找ESRCH
的返回值-1和errno
来指示进程离开了。更新:从 linux 内核 5.3 开始,有一个 pidfd_open syscall,它为给定的 pid 创建一个 fd,当 pid 退出时可以轮询该 fd 以获取通知。
Nothing equivalent to
wait()
. The usual practice is to poll usingkill(pid, 0)
and looking for return value -1 anderrno
ofESRCH
to indicate that the process is gone.Update: Since linux kernel 5.3 there is a pidfd_open syscall, which creates an fd for a given pid, which can be polled to get notification when pid has exited.
在 BSD 和 OS X 上,您可以使用 kqueue 和 EVFILT_PROC+NOTE_EXIT 来完成此操作。 无需投票。 不幸的是,Linux 上没有类似的东西。
On BSDs and OS X, you can use kqueue with EVFILT_PROC+NOTE_EXIT to do exactly that. No polling required. Unfortunately there's no Linux equivalent.
到目前为止,我已经找到了三种在 Linux 上执行此操作的方法:
kill
或测试/ 是否存在proc/$pid
,如大多数其他答案一样netlink
接口监听PROC_EVENT_EXIT
消息 - 这样内核每次进程退出时都会告诉您的程序,您只需等待正确的进程 ID。 我只在互联网上的一个地方看到过这种描述。无耻的插件:我正在开发一个程序(当然是开源的;GPLv2),它可以执行以下任何操作三。
So far I've found three ways to do this on Linux:
kill
or by testing for the existence of/proc/$pid
, as in most of the other answersptrace
system call to attach to the process like a debugger so you get notified when it exits, as in a3nm's answernetlink
interface to listen forPROC_EVENT_EXIT
messages - this way the kernel tells your program every time a process exits and you just wait for the right process ID. I've only seen this described in one place on the internet.Shameless plug: I'm working on a program (open source of course; GPLv2) that does any of the three.
您还可以创建一个套接字或 FIFO 并读取它们。 FIFO 特别简单:将您孩子的标准输出与 FIFO 连接并读取。 读取将阻塞,直到子进程退出(出于任何原因)或直到它发出一些数据。 因此,您需要一个小循环来丢弃不需要的文本数据。
如果您有权访问子进程的源代码,请在子进程启动时打开 FIFO 进行写入,然后就可以忽略它。 当子进程终止时,操作系统将清除打开的文件描述符,并且您等待的“父”进程将被唤醒。
现在,这可能是一个不是您启动或拥有的过程。 在这种情况下,您可以将二进制可执行文件替换为启动真正二进制文件的脚本,同时还添加如上所述的监视。
You could also create a socket or a FIFO and read on them. The FIFO is especially simple: Connect the standard output of your child with the FIFO and read. The read will block until the child exits (for any reason) or until it emits some data. So you'll need a little loop to discard the unwanted text data.
If you have access to the source of the child, open the FIFO for writing when it starts and then simply forget about it. The OS will clean the open file descriptor when the child terminates and your waiting "parent" process will wake up.
Now this might be a process which you didn't start or own. In that case, you can replace the binary executable with a script that starts the real binary but also adds monitoring as explained above.
这是一种等待 linux 中的任何进程(不一定是子进程)退出(或被杀死)而无需轮询的方法:
使用 inotify 等待 /proc'pid' 被删除将是完美的解决方案,但不幸的是 inotify不适用于 /proc 等伪文件系统。
但是我们可以将它与进程的可执行文件一起使用。
当该进程仍然存在时,该文件将保持打开状态。
因此我们可以使用 inotify 和 IN_CLOSE_NOWRITE 来阻塞,直到文件关闭。
当然,它可能会因其他原因而关闭(例如,如果具有相同可执行文件的另一个进程退出),因此我们必须通过其他方式过滤这些事件。
我们可以使用kill(pid, 0),但这不能保证它是否仍然是同一个进程。 如果我们真的对此感到偏执,我们可以做点别的事情。
这是一种 100% 安全地防止 pid 重用问题的方法:我们打开伪目录 /proc/'pid',并保持它打开状态直到我们完成。 如果同时使用相同的 pid 创建一个新进程,我们持有的目录文件描述符仍将引用原始进程(或者如果旧进程不再存在,则变得无效),但永远不会引用新进程重用的 pid。 然后我们可以通过openat()检查目录中是否存在“cmdline”文件来检查原始进程是否仍然存在。 当进程退出或被终止时,这些伪文件也不再存在,因此 openat() 将失败。
这是一个示例代码:
Here is a way to wait for any process (not necessarily a child) in linux to exit (or get killed) without polling:
Using inotify to wait for the /proc'pid' to be deleted would be the perfect solution, but unfortunately inotify does not work with pseudo file systems like /proc.
However we can use it with the executable file of the process.
While the process still exists, this file is being held open.
So we can use inotify with IN_CLOSE_NOWRITE to block until the file is closed.
Of course it can be closed for other reasons (e.g. if another process with the same executable exits) so we have to filter those events by other means.
We can use kill(pid, 0), but that can't guarantee if it is still the same process. If we are really paranoid about this, we can do something else.
Here is a way that should be 100% safe against pid-reuse trouble: we open the pseudo directory /proc/'pid', and keep it open until we are done. If a new process is created in the meantime with the same pid, the directory file descriptor that we hold will still refer to the original one (or become invalid, if the old process cease to exist), but will NEVER refer the new process with the reused pid. Then we can check if the original process still exists by checking, for example, if the file "cmdline" exists in the directory with openat(). When a process exits or is killed, those pseudo files cease to exist too, so openat() will fail.
here is an example code:
您可以使用 ptrace(2) 附加到进程。 在 shell 中,
strace -p PID >/dev/null 2>&1
似乎可以工作。 这可以避免忙等待,尽管它会减慢跟踪进程的速度,并且不适用于所有进程(仅适用于您的进程,这比仅子进程好一点)。You could attach to the process with
ptrace(2)
. From the shell,strace -p PID >/dev/null 2>&1
seems to work. This avoid the busy-waiting, though it will slow down the traced process, and will not work on all processes (only yours, which is a bit better than only child processes).从 linux 内核 5.3 开始,有一个 pidfd_open 系统调用,它创建给定 pid 的 fd,可以轮询它以在 pid 退出时获取通知。
Since linux kernel 5.3 there is a pidfd_open syscall, which creates an fd for a given pid, which can be polled to get notification when pid has exited.
我不知道。 除了混乱的解决方案之外,如果您可以更改要等待的程序,则可以使用信号量。
库函数为
sem_open(3)
、sem_init(3)、
sem_wait(3)、
...sem_wait(3)
执行等待,因此您不必像混沌解决方案中那样忙于等待。 当然,使用信号量会让你的程序变得更加复杂,而且可能不值得这么麻烦。None I am aware of. Apart from the solution from chaos, you can use semaphores if you can change the program you want to wait for.
The library functions are
sem_open(3)
,sem_init(3),
sem_wait(3),
...sem_wait(3)
performs a wait, so you don´t have to do busy waiting as in chaos´ solution. Of course, using semaphores makes your programs more complex and it may not be worth the trouble.也许可以等待 /proc/[pid] 或 /proc/[pid]/[something] 消失?
有 poll() 和其他文件事件等待函数,也许这可以帮助?
Maybe it could be possible to wait for /proc/[pid] or /proc/[pid]/[something] to disappear?
There are poll() and other file event waiting functions, maybe that could help?
PR_SET_PDEATHSIG 可用于等待父进程终止
PR_SET_PDEATHSIG can be used to wait for parent process termination
我的解决方案(使用
inotifywait
)这是基于 linux 的
/proc
文件系统。我的需要是在容器备份完成后启动第二次(整体)备份。 容器备份由 cron。
监视
cron
任务其中 已删除 条目是由
cron
创建的。 但即使删除,您也可以直接监视文件描述符:或
注意:我的整体备份运行为root用户! 如果没有,这可能需要
sudo
因为命令是在cron
会话下运行的!同一会话
只需测试:在第一个窗口中,点击:
然后在另一个窗口中:
不要尝试观看
1
或2
! 因为它们指向/dev/null
,所以任何访问它们的进程都会触发inotifywait
。经过的时间(以秒为单位)
第一个窗口:
第二个窗口:
结论。
使用inotifywait似乎是一个很好的解决方案,主要是监视命令的标准输入(fd/0)。 但这必须根据具体情况进行测试。
My solution (using
inotifywait
)This is based on linux's
/proc
filesystem.My need was to start a 2nd (overall) backup, once containers backups is done. Containers backups is started by cron.
Watching for
cron
tasksWhere deleted entries was created by
cron
. But even if deleted, you could watch for file descriptor directly:or
Note: My overall backup is run as root user! If no this could require
sudo
because command is run undercron
session!Same session
Just test: In a 1st window, hit:
Then in another window:
Don't try to watch for
1
or2
! Because they point to/dev/null
, any process acessing to them will triginotifywait
.Elapsed time in seconds
1st window:
2nd window:
Conclusion.
Using
inotifywait
seem to be a good solution, mostly watching for command's standard input (fd/0). But this must be tested case by case.只需轮询 /proc/[PID]/stat 的值 22 和 2。
值 2 包含可执行文件的名称,22 包含开始时间。
如果它们发生变化,则表明其他进程已采用相同(已释放)的 PID。 因此该方法是非常可靠的。
Simply poll values number 22 and 2 of the /proc/[PID]/stat.
The value 2 contains name of the executable and 22 contains start time.
If they change, some other process has taken the same (freed) PID. Thus the method is very reliable.
您可以使用
eBPF
来实现这一点。bcc
工具包基于eBPF
实现了许多优秀的监控能力。 其中exitsnoop
跟踪进程终止,显示命令名称和终止原因,要么是退出信号,要么是致命信号。
您可以参考该工具进行相关实现。
您可以通过以下链接获取有关该工具的更多信息:
你可以先安装这个工具并使用它看看是否满足你的需求,然后参考它的实现进行编码,或者使用它提供的一些库来实现自己的功能。
exitsnoop
示例:另一个选项
使用 Linux 的 PROC_EVENTS 等待(非子)进程退出
参考项目:
https://github.com/stormc/waitforpid
项目中提到的
You can use
eBPF
to achieve this.The
bcc
toolkit implements many excellent monitoring capabilities based oneBPF
. Among them,exitsnoop
traces process termination, showing the command name and reason for termination,either an exit or a fatal signal.
You can refer to this tool for related implementation.
You can get more information about this tool from the link below:
You can first install this tool and use it to see if it meets your needs, and then refer to its implementation for coding, or use some of the libraries it provides to implement your own functions.
exitsnoop
examples:Another option
Wait for a (non-child) process' exit using Linux's PROC_EVENTS
Reference project:
https://github.com/stormc/waitforpid
mentioned in the project:
使用 kqueue 适用于 macOS 的 @Hongli 答案。 我用快速实现它
Appricate @Hongli's answer for macOS with kqueue. I implement it with swift