PHP分叉和多个子信号

nic*_*ckf 8 php fork process

我正在尝试编写一个脚本,该脚本使用这些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 实现某种简单的锁定,其中一次只有一个孩子可以拥有说话棒。只要确保孩子们正常处理致命信号,以便他们保持活动状态以释放锁即可。