PHP分叉:当孩子变成僵尸时杀死它
我已经有了这段代码,它在我的各种php cli程序中非常适合我的需要。只是有时候孩子会变成僵尸 我的问题是在哪里放置代码来检查一个孩子是否运行了5分钟,以及是否比杀死它更长 我知道如何杀死posix_kill来杀死它,以及如何跟踪它 我不确定如何将这些新功能组合到代码中。每次我试图这样做,我都会陷入混乱。也许有人知道分叉可以修复我的代码 忽略所有的错误日志-我想看看它运行时发生了什么PHP分叉:当孩子变成僵尸时杀死它,php,php-5.3,Php,Php 5.3,我已经有了这段代码,它在我的各种php cli程序中非常适合我的需要。只是有时候孩子会变成僵尸 我的问题是在哪里放置代码来检查一个孩子是否运行了5分钟,以及是否比杀死它更长 我知道如何杀死posix_kill来杀死它,以及如何跟踪它 我不确定如何将这些新功能组合到代码中。每次我试图这样做,我都会陷入混乱。也许有人知道分叉可以修复我的代码 忽略所有的错误日志-我想看看它运行时发生了什么 public function __construct($data) { //Keep
public function __construct($data) {
//Keep track of all of the children processes
$this->children = Array();
//Specify the maximum number of child processes to fork at any given time
$this->max_children = 5;
}
private function process()
{
foreach ($collection as $stuff)
{
//FORK THE PROCESS
$pid = pcntl_fork();
//Something went wrong
if($pid == -1)
{
error_log ("could not fork");
die ();
}
//PARENT PROCESS
if($pid)
{
//error_log ("Parent: forked " . $pid);
$this->children[] = $pid;
}
//CHILD PROCESS
else
{
// Do stuff here
exit(); //Exit the child thread so it doesn't continue to process the data
}
//COLLECT ALL OF THE CHILDREN AS THEY FINISH
while( ($c = pcntl_wait($status, WNOHANG OR WUNTRACED) ) > 0)
{
//error_log ("Collected Child - " . $c);
$this->remove_thread($this->children, $c);
error_log ("children left: " . count($this->children));
}
//WAIT FOR A CHILD TO FINISH IF MAXIMUM PROCESSES IS EXCEEDED
if(sizeof($this->children) > $this->max_children)
{
//error_log ("Maximum children exceeded. Waiting...");
if( ($c = pcntl_wait($status, WUNTRACED) ) > 0)
{
//error_log ("Waited for Child - " . $c);
$this->remove_thread($this->children, $c);
error_log ("children left: " . count($this->children));
}
}
}
//COLLECT ALL OF THE CHILDREN PROCESSES BEFORE PROCEEDING
while( ($c = pcntl_wait($status, WUNTRACED) ) > 0){
//error_log ("Child Finished - " . $c);
$this->remove_thread($this->children, $c);
error_log ("children left: " . count($this->children));
}
}
//Function to remove elements from an array
private function remove_thread(&$Array, $Element)
{
for($i = 0; $i < sizeof($Array); $i++)
{
//Found the element to remove
if($Array[$i] == $Element){
unset($Array[$i]);
$Array = array_values($Array);
break;
}
}
}
公共函数uuu构造($data){
//跟踪所有子进程
$this->children=Array();
//指定在任何给定时间分叉的最大子进程数
$this->max_children=5;
}
私有函数进程()
{
foreach($stuff的集合)
{
//分岔
$pid=pcntl_fork();
//出了点问题
如果($pid==-1)
{
错误日志(“无法分叉”);
模具();
}
//父进程
如果($pid)
{
//错误日志(“父项:分叉”。$pid);
$this->children[]=$pid;
}
//子进程
其他的
{
//在这里做事
exit();//退出子线程,使其不再继续处理数据
}
//孩子们讲完后把他们都集合起来
而($c=pcntl_wait($status,WNOHANG或WUNTRACED))>0)
{
//错误日志(“收集的子项-”$c);
$this->remove_线程($this->children,$c);
错误日志(“离开的子项:“.count($this->children));
}
//如果超过最大进程数,请等待子进程完成
if(sizeof($this->children)>$this->max\u children)
{
//错误日志(“超过了最大子项。正在等待…”);
如果($c=pcntl_wait($status,WUNTRACED))>0)
{
//错误日志(“等待子项-”$c);
$this->remove_线程($this->children,$c);
错误日志(“离开的子项:“.count($this->children));
}
}
}
//在继续之前收集所有子进程
而($c=pcntl_wait($status,WUNTRACED))>0){
//错误日志(“子完成-”$c);
$this->remove_线程($this->children,$c);
错误日志(“离开的子项:“.count($this->children));
}
}
//函数从数组中删除元素
私有函数remove_线程(&$Array,$Element)
{
对于($i=0;$i
首先:WNOHANG或WUNTRACED
等于(bool-true),WNOHANG | WUNTRACED
为int(3),产生了很大的差异,尽管在这里不一定
//set maximum child time.
$maxruntime = 300;
//.....
//..... skip a lot of code, prefer trigger_error($msg,E_USER_ERROR) above die($msg) though
//.....
//if we are the parent
if($pid)
{
//store the time it started
$this->children[$pid] = time();
}
//.....
//..... skip
//.....
//COLLECT ALL OF THE CHILDREN AS THEY FINISH
while(count($this->children) > 0){
//copy array as we will unset $this->children items:
$children = $this->children;
foreach($children as $pid => $starttime){
$check = pcnt_waitpid($pid, $status, WNOHANG | WUNTRACED);
switch($check){
case $pid:
//ended successfully
unset($this->children[$pid];
break;
case 0:
//busy, with WNOHANG
if( ( $starttime + $maxruntime ) < time() || pcntl_wifstopped( $status ) ){
if(!posix_kill($pid,SIGKILL)){
trigger_error('Failed to kill '.$pid.': '.posix_strerror(posix_get_last_error()), E_USER_WARNING);
}
unset($this->children[$pid];
}
break;
case -1:
default:
trigger_error('Something went terribly wrong with process '.$pid, E_USER_WARNING);
// unclear how to proceed: you could try a posix_kill,
// simply unsetting it from $this->children[$pid]
// or dying here with fatal error. Most likely cause would be
// $pid is not a child of this process.
break;
}
// if your processes are likely to take a long time, you might
// want to increase the time in sleep
sleep(1);
}
//设置最长子时间。
$maxruntime=300;
//.....
//..... 跳过很多代码,但更喜欢触发器错误($msg,E_USER_error)而不是die($msg)
//.....
//如果我们是父母
如果($pid)
{
//存储它开始的时间
$this->children[$pid]=time();
}
//.....
//..... 跳过
//.....
//孩子们讲完后把他们都集合起来
而(计数($this->children)>0){
//复制数组,因为我们将取消设置$this->children项:
$children=$this->children;
foreach($pid=>$starttime的子项){
$check=pcnt|U waitpid($pid,$status,WNOHANG | WUNTRACED);
交换机($check){
案例$pid:
//圆满结束
未设置($this->children[$pid];
打破
案例0:
//忙,和WNOHANG在一起
如果($starttime+$maxruntime)
以下是我摆脱僵尸进程的方法……孩子们甚至可以与stdin交谈,他们的僵尸会在终止过程中被杀死(SIGCHLD)。无需等待任何东西,完全异步
<?php
declare(ticks = 1); // cpu directive
$max=10;
$child=0;
$children = array();
function sig_handler($signo) { // we release zombie souls in here, optimal place - shot exactly after childs death.
global $child,$children;
switch ($signo) {
case SIGCHLD:
$child -= 1;
foreach($children as $pid){
$res = pcntl_waitpid($pid,$status, WNOHANG | WUNTRACED);
if($res != 0) unset($children[$pid]);
}
}
}
pcntl_signal(SIGCHLD, "sig_handler"); // register fork signal handler to count running children
while (true){ // <main_loop> - could be whatever you want, for, while, foreach... etc.
while ($child >= $max) {
sleep(1);
}
$child++;
$pid=pcntl_fork();
if($pid == -1){
}else if($pid){
$children[$pid] = $pid; // register new born children
}else{ // <fork>
echo "HELLO DADDY! I'M ALIVE! I CAN DO WHATEVER YOU WANT, DAD.";
sleep(1); // avoid segmentation fault, when fork ends before handling signals
exit(0);
} // </fork>
// optional timer between child spawn, avoiding wakeup on SIGCHLD
$timeLeft = 5; // 5 seconds
while ($timeLeft > 0) {
$timeLeft = sleep($timeLeft);
}
} // </main_loop>
while($child != 0){
sleep(1);
}
?>
真棒的标题…孩子们变成僵尸是因为他们没有被收割,而不是因为他们还活着…@Ignacio-有这样的例子,比如说,我正在通过curl检查代理。有时,孩子们会因为curl已解卡而变得无反应,如果我迟早要检查1000个代理,那么我的所有孩子都会变成僵尸re zombified.这是一个我需要知道它们已经运行了多长时间的例子,这样我才能杀死它们并生下新的孩子。我的评论仍然有效。当然,但以我的经验,你错了:)谢谢你的努力,我真的很感激。我很快会看一看,然后回来。注意unset($this->children[$pid];
带有案例0: