2013-04-26 72 views
2

所以,我有這個PHP後臺工作人員監聽到IPC消息。 奇怪的是,父進程(從pcntl_fork結果)離開[PHP] <解散>進程,直到子進程完成,但只有當腳本啓動命令行形成一個cronjob,不直接。pcntl_fork()導致倒閉的父進程

我知道<解散>過程不是邪惡的,而是從一個cronjob運行時,我想不通爲什麼它只是發生。

命令

/path/to/php/binary/php /path/to/php/file/IpcServer.php 

分岔代碼:

$iParent = posix_getpid(); 
$iChild = pcntl_fork(); 

if ($iChild == -1) 
    throw new Exception("Unable to fork into child process."); 

elseif ($iChild) 
{ 
    echo "Forking into background [{$iChild}].\n"; 

    Log::d('Killing parent process (' . $iParent. ').'); 
    exit; 
} 

輸出

Forking into background [20835]. 
Killing parent process (20834). 

ps aux | grep的PHP

root 20834 0.0 0.0 0 0 ? Zs 14:28 0:00 [php] <defunct> 
root 20835 0.0 0.2 275620 8064 ? Ss 15:35 0:00 /path/to/php/binary/php /path/to/php/file/IpcServer.php 

,我發現這是一個衆所周知的Apache錯誤,但隨後從運行的cronjob時,爲什麼會出現這樣的錯誤?

+0

我有相同的問題,但是我跑我的PHP守護進程通過[Upstart](http://upstart.ubuntu.com/cookbook/)。我的申請分叉一次。通過Upstart啓動父進程成爲殭屍。通過CLI啓動 - 無父進程殭屍。 – user12345 2014-07-26 17:55:42

回答

2

在PHP中,孩子將成爲一個殭屍進程,除非父母等待它返回pcntl_wait()pcntl_waitpid()。所有進程結束或處理後,殭屍將被銷燬。如果孩子沒有得到處理,並且孩子比父母長,那麼父母看起來也會變成殭屍。

來自實例pcntl_fork頁:

$pid = pcntl_fork(); 
if ($pid == -1) { 
    die('could not fork'); 
} else if ($pid) { 
    // we are the parent 
    pcntl_wait($status); //Protect against Zombie children 
} else { 
    // we are the child 
} 

或者使用信號處理,像這樣以防止等待主線程:

$processes = array(); // List of running processes 
$signal_queue = array(); // List of signals for main thread read 
// register signal handler 
pcntl_signal(SIGCHLD, 'childSignalHandler'); 

// fork. Can loop around this for lots of children too. 
switch ($pid = pcntl_fork()) { 
    case -1: // FAILED 
     break; 
    case 0: // CHILD 
     break; 
    default: // PARENT 
     // ID the process. Auto Increment or whatever unique thing you want 
     $processes[$pid] = $someID; 
     if(isset($signal_queue[$pid])){ 
      childSignalHandler(SIGCHLD, $pid, $signal_queue[$pid]); 
      unset($signal_queue[$pid]); 
     } 
     break; 
} 

function childSignalHandler($signo, $pid=null, $status=null){ 
    global $processes, $signal_queue; 
    // If no pid is provided, Let's wait to figure out which child process ended 
    if(!$pid){ 
     $pid = pcntl_waitpid(-1, $status, WNOHANG); 
    } 

    // Get all exited children 
    while($pid > 0){ 
     if($pid && isset($processes[$pid])){ 
      // I don't care about exit status right now. 
      // $exitCode = pcntl_wexitstatus($status); 
      // if($exitCode != 0){ 
      //  echo "$pid exited with status ".$exitCode."\n"; 
      // } 
      // Process is finished, so remove it from the list. 
      unset($processes[$pid]); 
     } 
     else if($pid){ 
      // Job finished before the parent process could record it as launched. 
      // Store it to handle when the parent process is ready 
      $signal_queue[$pid] = $status; 
     } 
     $pid = pcntl_waitpid(-1, $status, WNOHANG); 
    } 
    return true; 
} 
+0

我有一個殭屍父母,而不是孩子。但是你是否說我的父母程序應該經常等待孩子完成?對於我來說,當主要目標是進行守護進程時沒有任何意義。 – Milananas 2013-05-02 09:31:32

+0

啊,我誤解了你的問題。我相信你也可以用pcntl_signal來防止殭屍小孩,但我並不擅長PHP進程。我懷疑所有PHP進程成爲殭屍(父母或子女),如果他們結束,而其他進程仍在運行不處理。 – 2013-05-02 17:00:20

+0

我的孩子和父母進程都有適當的信號處理。我現在正在調查是否也許是PHP不是垃圾清理父進程真的很好,因爲孩子使用一些資源從父進程。 – Milananas 2013-05-03 06:48:56