我有一个程序,它通常运行到终止,但在某些情况下,它创建了两个子进程,然后主进程退出。主进程退出后,子进程将继续运行。
我想在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']是假的,但是子进程仍然在运行。如何真正等待所有子进程?
第二个问题是我没有研究proc_terminate,但我也观察到proc_terminate可能不像我预期的那样工作。这是因为$process是bash而不是真正的python进程吗?这也可能是因为我终止的只是父主进程,而不是子进程。
有没有人告诉我,上面的代码是不是健壮的PHP代码?有更好的办法来处理这件事吗?
谢谢。
======================
更多的信息,
我在shell (CLI)中运行这个程序,与CGI函数无关。所以我不需要担心max_execution_time。
我想等待proc_open打开的主进程创建的子进程,我将只在程序中创建一个进程。
我想调用的python程序可能会挂起很长时间,所以我想检查超时并终止它
proc_get_status可以获取子进程的pid
$status = proc_get_status($process);
$pid = $status["pid"]
则可以使用pcntl_waitpid
等待子进程退出
pcntl_waitpid($pid, $child_status);
但是你需要用pcntl
扩展来编译你的php。
参见PCNTL Functions
UPDATE:如果你想在超时后杀死子进程
首先:在主进程中安装SIGALARM
处理程序
function term_proc() {
// terminate your all child process
}
pcntl_signal(SIGALARM, term_proc);
秒:用pcntl_alarm
在秒后发出报警信号
pcntl_alarm($seconds)
对于第二个问题,无论打开什么进程,proc_terminate
都可以工作。
如果您不打算以某种方式与生成的进程交互(例如通过重定向其输入或输出),那么您可以使用system
而不是proc_open
。system
将等待生成的进程完成,所以不需要经常检查它。
小心:等待另一个进程可能会导致您的脚本因超出max_execution_time
而终止。它也可能不能很好地与你的web服务器的内部管理执行单元。
Update:似乎你想启动一个进程X,然后等待进程X自己启动的所有进程退出,然后再继续。我很抱歉成为坏消息的承担者,但PHP不是为这种类型的工作而设计的,您所追求的是不可能实现的股票PHP。当然可以用C编写一个自定义扩展来公开此功能,但据我所知,没有这样的扩展公开可用。
父进程很难遵循其所有子进程的 。只有在儿童直接死亡的情况下才会通知程序。您可以采用几种不同的机制来尝试做您想做的事情,但最好是重写您的应用程序,以不关心您的进程的孙子。
-
cgroups
为systemd
提供了足够的机制来跟踪从单个初始execve(2)
调用开始的所有子进程。虽然您可以自己使用
cgroups
,但我还没有了解到试图使用cgroups
进行过程管理的后果,而systemd
或libvirt
或其他工具可能正在做类似的事情。(这是我的无知,而不是cgroups
的局限性——也许它处理得很好。我喜欢做梦。 -
在进程中打开
pipe(2)
,并在文件描述符中为子进程创建pipe(7)
的读端,该文件描述符足够高,不会"意外"使用。(dup2(fd[0], 20)
可能是好的)确保您的其他程序不会关闭意外的文件描述符。使用fcntl(2)
的F_SETFL
命令设置写端(fd[1]
)的O_NONBLOCK
标志。定期尝试将一个字节写入管道。最终,您将获得
EPIPE
错误返回,指示读端已被所有子进程关闭,或者您将获得errno
设置为EAGAIN
的错误返回,这意味着管道满并且仍然有子进程在运行。