2012-02-06 4 views
5

私は、私の様々なPHPのcliプログラムで自分のニーズに完全に動作するこのコードブロックを持っています。ただし、時には子供がゾンビになることを除けば。PHPフォーク:ゾンビになると子供を殺す

私の質問は、子供が5分間発言するかどうかを確認するコードをどこに置くのか、そしてそれが長くなるとそれを殺すことですか?

私はそれを殺すためにposix_killについて知っており、それをどのように追跡するのですか? There are examples of taskmanagers here

これらの新機能をコードに組み込む方法がわかりません。私がしようとするたびに、私はちょうど混乱に陥る。おそらく、フォークを知っている人が自分のコードを修正できますか?

すべてのerror_logを無視します。実行時に何が起きているのが好きです。すべての

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; 
     } 
    } 
} 
+9

素晴らしいタイトル... –

+1

子供たちは...彼らはまだ生きているではないので、ゾンビになっ –

+0

@Ignacio - と言う、私はカール経由でプロキシをチェックしていますインスタンスがあります。 Curlが解体してしまったために子供が反応しなくなると、1000代の代理人を早急にチェックしていれば、すべての子どもがゾンビ化されます。それは、私がそれらを殺して新しい子供を作ることができるように、彼らがどれくらいの期間走っているのかを知る必要がある1つの事例です。 – PaulM

答えて

1

まず:WNOHANG OR WUNTRACED等号(BOOL真)は、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); 
    } 
+0

ありがとう、本当にありがとうございます。私はこれをすぐに見て、戻ってくるだろう。 – PaulM

+0

if caseにある 'unset($ this-> children [$ pid];')はif文に入れるべきであることに注意してください...答えを編集しました。そうしないと、配列全体を無差別にunsetします。 – Wrikken

0

は、子どもたちにも標準入力に話すことができ、そのゾンビが終了(SIGCHLD)の間に殺されてしまいます...ゾンビプロセスを退治に私のために働いていたものです。何も待たずに、全く非同期です。 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); 
    } 

    ?> 

タイマーは、その方法を実装する必要があります()。それについての情報とそれを回避する方法については、SztupYへのクレジットを参照してください。彼らは刈り取られていないので、

関連する問題