I have the following test php to do a fork/spawn process, where the test also attempts to kill the child process (zombie) after is completes..
I'd like to have a more efficient process, where any child processes are immediately removed from the process table as soon as possible. The current attempt fills up the process table, and causes a memory allocation issue that shuts down the system. The app is running on a Fedora/Centos system.
I'm running into a memory allocation err when this runs, and there are too many processes that get spawned, before they get removed.
Any pointers would be greatly appreciated on this thanks..
$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";
}
update::: managed to get what i think is a solution.....
//--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;
}
}
Just use pcntl_wait(). There's no need to see if the child process has finished, just call pcntl_wait() and block until the child is reaped.
Avoid passing WNOHANG so that your parent process will sit and wait for a child to finish.
You can replace the reaping code you've written (starting at line 58 '$q=true;' of your example) with this:
$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);
Fork in foreach:
<?
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
}
}
?>
来源:https://stackoverflow.com/questions/5024934/php-forking-issue