我有以下测试php来做fork / spawn进程,测试也会在完成后尝试终止子进程(僵尸)。
我希望有一个更高效的流程,其中任何子流程都会立即从流程表中立即删除。当前尝试填满进程表,并导致关闭系统的内存分配问题。该应用程序在Fedora / Centos系统上运行。
当它运行时,我遇到内存分配错误,并且在删除之前有太多的进程被生成。
在此感谢任何指针都会非常感激..
$fname="ef_deptData.txt";
$t=0;
$pids = array();
$pids1[] = array();
$fh=fopen($fname,"r");
$p=0;
while(!feof($fh))
{
print " inside course pppppppppppppppppppppp \n";
//--go ahead and parse the line of input from the file
//--(if it exists)
$buf = fgets($fh);
$buf=trim($buf);
if($buf)
{
$data1=explode("&&",$buf);
$stateVal=trim($data1[0]);
$collegeVal=trim($data1[1]);
$campusVal=trim($data1[2]);
$pid = pcntl_fork();
//process the spawned child procs
if($pid)
{
$pids[$p]=$pid;
$p=$p+1;
}
else
{
$app="ef_course.py";
$args[0]='"'.$stateVal.'"';
$args[1]='"'.$collegeVal.'"';
$args[2]='"'.$campusVal.'"';
pcntl_exec($app, $args);
}
}
$t=$t+1;
if($t==40)
{
sleep(5);
$t=0;
}
}
// --this section is a kludge to see if the child process is complete
// --prior to deleting the spwaned child process (should be a better way)
$q=true;
while($q)
{
$a="ps -aux | grep ef_course | grep -v grep | awk '{print $8}'";
$a=`$a`;
$t=explode("\n",$a);
$t=array_slice($t,1,-1);
print_r($t);
sleep(5);
$y=0;
for($i=0;$i<count($t);$i++)
{
if((strcmp($t[$i],"Z+")!=0)&&(strcmp($t[$i],"Z")!=0))
{
$y=1;
print "ddd \n";
}
}
if($y==0)
{
//--try to go ahead and kill the zombie processes
$w="pgrep ef_course";
$r=`$w`;
if($r!="")
{
//foreach($pids as $p){ posix_kill($p,SIGHUP); }
//foreach($pids as $p){ posix_kill($p,SIGINT); }
foreach($pids as $p){ posix_kill($p,SIGTERM); }
$dead_and_gone = pcntl_waitpid(-1,$status,WNOHANG);
while($dead_and_gone > 0){
// Remove the gone pid from the array
unset($pids[array_search($dead_and_gone,$pids)]);
// Look for another one
$dead_and_gone = pcntl_waitpid(-1,$status,WNOHANG);
}
print_r($pids);
}
else
$q=false;
}
sleep(10);
print "waiting for ef_course.py to complete \n";
}
更新::: 设法得到我认为是解决方案.....
//--start the process to get the store urls..
$fname="ef_programData.txt";
$t=0;
$pids = array();
$pids1[] = array();
$fh=fopen($fname,"r");
$p=0;
while(!feof($fh))
{
print " inside program pppppppppppppppppppppp \n";
//--go ahead and parse the line of input from the file
//--(if it exists)
$tmp=array();
$buf = fgets($fh);
$buf=trim($buf);
if($buf)
{
$data1=explode("&&",$buf);
$pid = pcntl_fork();
//process the spawned child procs
if($pid)
{
$pids[]=$pid;
}
else
{
$args=array();
$app="foo.py";
$args[0]='"'.$stateVal.'"';
pcntl_exec($app, $args);
}
while(pcntl_wait($status, WNOHANG) > 0) {
usleep(500);
}
while(list($key, $val) = each($pids)) {
if(!posix_kill($val, 0)) { // This detects if the child is still running or not
unset($pids[$key]);
}
}
$pids = array_values($pids); // Reindex the array
}
$t=$t+1;
if($t==40)
{
sleep(5);
$t=0;
}
}
答案 0 :(得分:2)
只需使用pcntl_wait()。没有必要查看子进程是否已经完成,只需调用pcntl_wait()并阻塞直到孩子被收获。
避免传递WNOHANG,以便您的父进程坐下来等待孩子完成。
你可以用以下代码替换你所写的收割代码(从你的例子的第58行'$ q = true;'开始):
$status = null;
do {
// You can use $status with pcntl_wifexited(), pcntl_wifstopped(),
// pcntl_wifsignaled(), pcntl_wexitstatus(), pcntl_wtermsig() and
// pcntl_wstopsig() if you need to.
$pid = pcntl_wait($status);
} while ($pid > 0);
答案 1 :(得分:1)
分道扬:
<?
declare(ticks=1);
pcntl_signal(SIGUSR1, create_function('$signo', 'sleep(1);while (($pid=pcntl_wait(@$status, WNOHANG))>0) {}'));//protect against zombie children
foreach ($tasks as $v)
{if (($pid=pcntl_fork())===-1)
{//...
continue;
}
else if ($pid===0)
{ob_start();//prevent output to main process
register_shutdown_function(create_function('$pars', 'ob_end_clean();posix_kill(posix_getppid(), SIGUSR1);posix_kill(getmypid(), SIGKILL);'), array());//to kill self before exit();, or else the resource shared with parent will be closed
//...
exit();//avoid foreach loop in child process
}
}
?>