我正在尝试编写一个脚本,该脚本使用这些pcntl_*函数创建了许多分叉的子进程.
基本上,有一个脚本在循环中运行大约一分钟,定期轮询数据库以查看是否有要运行的任务.如果有一个,它应该在一个单独的进程中分叉并运行该任务,以便父进程不会被长时间运行的任务阻止.
由于可能有大量任务准备好运行,我想限制创建的子进程数.因此,我通过在每次创建变量时递增变量来跟踪进程数(然后暂停,如果有太多),然后在信号处理程序中递减它.有点像这样:
define(ticks = 1);
$openProcesses = 0; // how many we have open
$max = 3; // the most we want open at a time
pcntl_signal(SIGCHLD, "childFinished");
while (!time_is_up()) {
if (there_is_something_to_do()) {
$pid = pcntl_fork();
if (!$pid) { // I am the child
foo(); // run the long-running task
exit(0); // and exit
} else { // I am the parent
++$openProcesses;
if ($openProcesses >= $max) {
pcntl_wait($status); // wait for any child to exit
} // before continuing
}
} else {
sleep(3);
}
}
function childFinished($signo) {
global $openProcesses;
--$openProcesses;
}
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下都可以正常工作,除非两个或多个进程同时完成 - 信号处理函数只调用一次,这会抛出我的计数器.其原因可以通过PHP手册中的"Anonymous"来解释:
多个子节点返回的次数少于在给定时刻退出的子节点数SIGCHLD信号是Unix(POSIX)系统的正常行为.SIGCHLD可能被解读为"一个或多个孩子改变了状态 - 去检查你的孩子并收集他们的状态值".
我的问题是:我如何检查孩子并收获他们的身份?有没有可靠的方法来检查在任何给定时间打开多少子进程?
使用PHP 5.2.9
小智 0
您可以让子级在启动时向父级发送 SIGUSR1,然后在退出前向父级发送 SIGUSR2。使用原始信号时要处理的另一件事是内核合并它们,而 RT 信号则不会这样做。理论上,任何非 rt 信号都可以合并。
您可以使用 sqlite 实现某种简单的锁定,其中一次只有一个孩子可以拥有说话棒。只要确保孩子们正常处理致命信号,以便他们保持活动状态以释放锁即可。