2012-02-06 24 views
5

बन जाता है तो बच्चे को मार दें मुझे कोड का यह ब्लॉक मिला है जो मेरे विभिन्न PHP क्लिप कार्यक्रमों में मेरी आवश्यकताओं के लिए पूरी तरह से काम करता है। सिवाय इसके कि कभी-कभी एक बच्चा ज़ोंबी बन जाएगा।PHP फोर्किंग: जब यह ज़ोंबी

मेरा प्रश्न यह है कि कोई बच्चा 5 मिनट के लिए कहता है कि क्या यह जांचने के लिए कोड रखना है और यदि यह लंबे समय तक इसे मारने के लिए है?

मुझे यह जानने के लिए posix_kill के बारे में पता है और इसका ट्रैक कैसे रखें। There are examples of taskmanagers here

मुझे यकीन है कि कोड में इन नई सुविधाओं को कैसे जोड़ना है। हर बार जब मैं कोशिश करता हूं, मैं बस एक गड़बड़ में मिलता हूं। हो सकता है कि कोई जो फोर्किंग के बारे में जानता हो, मेरे कोड को ठीक कर सकता है?

सभी त्रुटि_लॉगों को अनदेखा करें - मुझे यह देखना पसंद है कि यह कब चल रहा है। सब से

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 - वहाँ उदाहरण है जब कहते हैं, मैं कर्ल के माध्यम से एक प्रॉक्सी जाँच कर रहा हूँ कर रहे हैं। ऐसे समय होंगे जब वह बच्चा उत्तरदायी नहीं हो जाता है क्योंकि कर्ल अस्थिर हो गया है और फिर यदि मैं जल्द ही या बाद में 1000 प्रॉक्सी जांच रहा हूं तो मेरे सभी बच्चे ज़ोंबीकृत हैं। तो यह एक उदाहरण है जहां मुझे यह जानने की जरूरत है कि वे कितने समय तक चल रहे हैं इसलिए मैं उन्हें मार सकता हूं और नए बच्चों को बना सकता हूं। – PaulM

उत्तर

1

पहले: WNOHANG OR WUNTRACED बराबर (bool सच है), WNOHANG | WUNTRACED पूर्णांक (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

नोट करें 'अनसेट ($ this-> बच्चे [$ pid]; 'केस 0:' के साथ अगर कथन में होना चाहिए ... बस जवाब संपादित किया गया है, अन्यथा आप पूरी सरणी को अनजाने में अनसेट कर देंगे। – Wrikken

0

यहाँ ज़ोंबी प्रक्रियाओं से छुटकारा पाने में मेरे लिए काम किया है ... बच्चों भी stdin से बात कर सकते हैं, उनके लाश समाप्ति (SIGCHLD) के दौरान हत्या कर दी हो जाएगा। कुछ भी इंतजार नहीं, पूरी तरह से async। क्योंकि 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 पर क्रेडिट करें और यह विचार करें कि इससे कैसे बचें।

संबंधित मुद्दे