2011-12-08 83 views
1

我有一個程序通常運行直到它終止,但在某些情況下,它創建了兩個子進程,然後主進程退出。主流程退出後,子進程仍將繼續運行。如何等待進程終止(並等待相應的子進程)在PHP中?

我想用PHP調用這個程序。

本來,我用下面的策略(沒有有效的PHP代碼),

$process=proc_open("python xxx.py"); 
while (1) { 
    sleep(5); 
    $status = proc_get_status($process); 
    if (!$status['running']) { 
     exit_loop; 
    } 
    if (timeout) { 
     proc_terminate($process, 9); 
     exit_loop; 
    } 
} 

但後來我很快就發現,該過程實際上會馬上退出[「運行」]即$狀態是假的bug,但兒童進程仍在運行。如何實際等待所有兒童進程?

第二個問題是我沒有看過proc_terminate,但我也觀察到proc_terminate可能無法正常工作。那是因爲$進程是一個bash,但不是真正的python進程?這也可能是因爲我終止的只是父母的主要過程,而不是子過程。

任何人都會告訴我,上面的代碼是否健壯的PHP代碼?有沒有更好的方法來解決這個問題?

謝謝。

======================

更多信息,

  1. 我在shell中運行這個程序(CLI)與CGI功能無關。所以我不需要擔心max_execution_time。

  2. 我想等待由proc_open打開的主進程創建的子進程,我只會在程序中創建一個進程。

  3. 我想調用的python程序可能會掛起很長時間,所以我想檢查超時並終止它。

回答

2

proc_get_status可以得到子進程

$status = proc_get_status($process); 
$pid = $status["pid"] 

的PID那麼你可以使用pcntl_waitpid等到子進程退出

pcntl_waitpid($pid, $child_status); 

但是你需要有你的PHP與pcntl擴展編譯。

PCNTL Functions

UPDATE:如果你想在超時後殺子過程

第一:在主過程中安裝一個SIGALARM處理

function term_proc() { 
    // terminate your all child process 
} 

pcntl_signal(SIGALARM, term_proc); 

二:使用pcntl_alarm來秒後發出報警信號

pcntl_alarm($seconds) 

對於第二個問題,proc_terminate無論打開哪個進程都可以工作。

2

如果您不打算以某種方式衍生的進程(例如通過重定向其輸入或輸出)進行交互,那麼你可以使用system而不是proc_opensystem將等待產生的過程完成,因此不需要經常檢查它。

注意:等待另一個進程可能會導致腳本因超過max_execution_time而被終止。它也可能無法與您的Web服務器對執行單元的內部管理相配合。

更新:您似乎想要啓動一個進程X,然後等待進程X本身啓動退出,然後再繼續。我很抱歉成爲壞消息的持有者,但PHP並不打算用於這種類型的工作,並且您所追求的內容無法通過股票PHP實現。用C編寫的自定義擴展肯定有可能公開這個功能,但據我所知,這種擴展沒有公開可用。

+0

感謝您的回答。 我在shell(CLI)中運行這個程序,並且與CGI函數無關。所以我不需要擔心max_execution_time。 我想等待由proc_open打開的主進程創建的子進程,我只會在程序中創建一個進程。 最後,使用其他程序可能會掛起很長時間的python程序,所以我想檢查超時並終止它。系統()可能不會終止超時我想? – user534498

+0

@ user534498:啊,我明白了。更新了答案,但遺憾的是,你想要做的並不是PHP中可行的(至少沒有定製的PHP擴展)。 – Jon

1

父母過程很難跟隨其後代的全部。只有直接的兒童死亡通知過程。你可以採取幾種不同的機制來嘗試做你想做的事情,但最好是重寫你的應用程序,而不關心你的進程的孫子。

  • cgroups提供了足夠的機制systemd遵循所有的子進程從一個單一的初始execve(2)通話開始。

    雖然你可以使用自己cgroups,我還沒有學到了很多的嘗試使用cgroups過程管理,同時systemdlibvirt或其他工具可能會做類似的事情的後果。 (這是我的無知比cgroups的限制更多 - 也許它處理它漂亮,我喜歡做夢。)

  • 打開您的過程中pipe(2),並給予在創建子進程的pipe(7)的讀端文件描述符足夠高,不會被「意外」使用。 (dup2(fd[0], 20)可能是好的。)確保您的其他程序不關閉意外的文件描述符。使用fcntl(2)F_SETFL命令在寫入結束(fd[1])上設置O_NONBLOCK標誌。

    定期嘗試在管道中寫入一個字節。最終,您將得到EPIPE錯誤返回信息,表明讀取結束已被所有孩子關閉,或者您將得到一個錯誤返回信息errno設置爲EAGAIN這意味着管道爲已滿並且仍有一個孩子正在運行。