Question

J'ai le test suivant PHP pour effectuer un processus de fourche / d'apparition, où le test tente également de tuer le processus de l'enfant (zombie) après être terminé.

J'aimerais avoir un processus plus efficace, où tous les processus d'enfants sont immédiatement supprimés du tableau de processus dès que possible. La tentative actuelle remplit la table de processus et provoque un problème d'allocation de mémoire qui arrête le système. L'application s'exécute sur un système Fedora / CentOS.

Je rencontre une allocation de mémoire ERR lorsque cela s'exécute, et il y a trop de processus qui sont engendrés, avant qu'ils ne soient supprimés.

Tous les pointeurs seraient grandement appréciés de cela merci.

$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";
}

Mise à jour ::: a réussi à obtenir ce que je pense être une 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;
            }
    }
Était-ce utile?

La solution

Utilisez simplement pcntl_wait (). Il n'est pas nécessaire de voir si le processus de l'enfant a terminé, appelez simplement PCNTL_WAIT () et Block jusqu'à ce que l'enfant soit récolté.

Évitez de passer wnohang afin que votre processus parent soit assis et attendez que un enfant se termine.

Vous pouvez remplacer le code de récolte que vous avez écrit (à partir de la ligne 58 '$ q = true;' de votre exemple) par ceci:

$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);

Autres conseils

Fourche dans 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
              }
        }
?>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top