php forking问题

时间:2011-02-17 04:01:47

标签: php memory fork spawn pcntl

我有以下测试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;
            }
    }

2 个答案:

答案 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
              }
        }
?>