我有一个程序通常运行直到它终止,但在某些情况下,它创建了两个子进程,然后主进程退出。主进程退出后,子进程仍将继续运行。
我想用PHP调用这个程序。
最初,我使用了以下策略(不是有效的PHP代码),
$process=proc_open("python xxx.py");
while (1) {
sleep(5);
$status = proc_get_status($process);
if (!$status['running']) {
exit_loop;
}
if (timeout) {
proc_terminate($process, 9);
exit_loop;
}
}
但后来我很快发现了这个进程实际上立即退出的错误,$ status ['running']为false,但是子进程仍在运行。如何实际等待所有孩子的过程?
第二个问题是我没有查看proc_terminate,但我也观察到proc_terminate可能无法正常工作。是因为$ process是bash而不是真正的python进程?也可能是因为我终止的只是父主进程而不是子进程。
任何人都建议我上面的代码是否是健壮的PHP代码?有没有更好的方法来解决这个问题?
感谢。
======================
更多信息,
我在shell(CLI)中运行此程序,与CGI函数无关。所以我不需要担心max_execution_time。
我想等待proc_open打开的主进程创建的子进程,我只会在程序中创建一个进程。
我想调用的python程序可能会挂起很长时间,所以我想检查超时并终止它。
答案 0 :(得分:2)
如果您不打算以某种方式与衍生过程进行交互(例如,通过重定向其输入或输出),则可以使用system
而不是proc_open
。 system
将等待生成的进程完成,因此无需经常检查它。
小心:等待其他进程可能会因超出max_execution_time
而导致脚本被终止。它可能也不适合您的Web服务器执行单元的内部管理。
更新:您似乎想要启动进程X,然后等待处理X本身启动的所有进程在继续之前退出。我很遗憾成为坏消息的承担者,但PHP并不适用于这类工作,而你所追求的目标不可能通过PHP库存来实现。当然可以用C语言编写自定义扩展来公开此功能,但据我所知,没有公开的此类扩展。
答案 1 :(得分:2)
proc_get_status可以获得子进程的pid
$status = proc_get_status($process);
$pid = $status["pid"]
然后您可以使用pcntl_waitpid
等待子进程退出
pcntl_waitpid($pid, $child_status);
但是你需要用pcntl
扩展名编译你的php。
更新:如果您想在超时后终止子进程
首先:在主进程中安装SIGALARM
处理程序
function term_proc() {
// terminate your all child process
}
pcntl_signal(SIGALARM, term_proc);
第二:使用pcntl_alarm
在秒后发送警报信号
pcntl_alarm($seconds)
对于第二个问题,proc_terminate
无论什么过程被打开都会有效。
答案 2 :(得分:1)
父进程很难跟踪所有的后代。只会通知直接儿童死亡的过程。您可以采取一些不同的机制来尝试做您想做的事情,但最好是重新编写您的应用程序而不关心您的流程的孙子。
cgroups
为systemd
提供了足够的机制来跟踪从单个初始execve(2)
调用开始的所有子进程。
虽然您可以自己使用cgroups
,但我在cgroups
或systemd
或其他工具时尝试使用libvirt
进行流程管理的后果并未了解多少可能在做类似的事情。 (这是我的无知,而不是cgroups
的限制 - 也许它处理得很漂亮。我喜欢做梦。)
在您的流程中打开pipe(2)
,并将文件描述符中创建的pipe(7)
的读取结尾提供给子进程,该文件描述符的大小不会“意外”使用。 (dup2(fd[0], 20)
可能很好。)确保您的其他程序不会关闭意外的文件描述符。在写入端设置O_NONBLOCK
标志(fd[1]
)使用fcntl(2)
的{{1}}命令。
定期尝试将一个字节写入管道。最终,您将获得F_SETFL
错误返回,表明读取结束已被所有孩子关闭或者您将收到错误,并将EPIPE
设置为errno
,这意味着管道是完整并且还有一个孩子正在跑步。