2012-02-06 87 views
5

我有這個代碼塊,它可以在我的各種php cli程序中完美地滿足我的需求。除了有時一個孩子會成爲殭屍。PHP分叉:當它變成殭屍時殺死孩子

我的問題是在哪裏放置代碼來檢查一個孩子是否跑5分鐘,如果它是更長的然後殺死它?

我知道posix_kill殺死它,以及如何跟蹤它。 There are examples of taskmanagers here。我不確定如何將這些新功能組合到代碼中。每次我嘗試,我都陷入一片混亂。也許有人知道分叉可以修復我的代碼?

忽略所有的error_logs - 我喜歡看它運行時發生了什麼。

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

真棒標題... – 2012-02-06 19:43:01

+1

孩子們成爲殭屍,因爲他們還沒有收穫,不是因爲他們還活着...... – 2012-02-06 19:52:08

+0

@Ignacio - 有實例說,我通過捲曲檢查代理。有時候這個孩子變得沒有反應,因爲Curl已經變得沒有了,然後如果我早晚檢查1000個代理,我的孩子們都會被殭屍化。所以這就是我需要知道他們已經跑了多久的一個例子,所以我可以殺死他們並且生下新的孩子。 – PaulM 2012-02-07 09:40:22

回答

1

首先:WNOHANG OR WUNTRACED的equals(BOOL TRUE),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 2012-02-07 21:10:10

+0

注意'unset($ this-> children [$ pid];'case 0:'應該在if語句中......只是編輯了答案,否則你將不加區別地取消整個數組。 – Wrikken 2012-02-07 21:13:01

0

下面是我擺脫殭屍進程的什麼工作......孩子甚至可以跟標準輸入,他們的殭屍會得到終止(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); 
    } 

    ?> 

定時器必須實施這種方式,因爲SIGCHLD喚醒每睡眠()。請致電SztupY瞭解相關信息並瞭解如何避免此類問題。