PHP多程序初探 孤兒和殭屍

2021-09-13 09:55:32 字數 3204 閱讀 4313

實際上,你們一定要記住:php的多程序是非常值得應用於生產環境具備**值的生產力工具。

但我認為在正式開始吹牛之前還是要說兩個基本概念:孤兒程序、殭屍程序。

上篇我整篇尬聊的都是pcntl_fork(),只管fork生產,不管產後護理,實際上這樣並不符合主流價值觀,而且,作業系統本身資源有限,這樣無限生產不顧護理,作業系統也會吃不消的。

孤兒程序是指父程序在fork出子程序後,自己先完了。這個問題很尷尬,因為子程序從此變得無依無靠、無家可歸,變成了孤兒。用術語來表達就是,父程序在子程序結束之前提前退出,這些子程序將由init(程序id為1)程序收養並完成對其各種資料狀態的收集。init程序是linux系統下的奇怪程序,這個程序是以普通使用者許可權執行但卻具備超級許可權的程序,簡單地說,這個程序在linux系統啟動的時候做初始化工作,比如執行getty、比如會根據/etc/inittab中設定的執行等級初始化系統等等,當然了,還有乙個作用就是如上所說的:收養孤兒程序。

殭屍程序是指父程序在fork出子程序,而後子程序在結束後,父程序並沒有呼叫wait或者waitpid等完成對其清理善後工作,導致改子程序程序id、檔案描述符等依然保留在系統中,極大浪費了系統資源。所以,殭屍程序是對系統有危害的,而孤兒程序則相對來說沒那麼嚴重。在linux系統中,我們可以通過ps -aux來檢視程序,如果有[z+]標記就是殭屍程序。

在php中,父程序對子程序的狀態收集等是通過pcntl_wait()和pcntl_waitpid()等完成的。依然還是要通過**還演示說明:

演示並說明孤兒程序的出現,並演示孤兒程序被init程序收養:

<?php 

$pid = pcntl_fork();

if( $pid > 0 ) else if( 0 == $pid )

} else

執行結果如下圖:

可以看到,前兩秒內,子程序的父程序程序id為4129,但是從第三秒開始,由於父程序已經提前退出了,子程序變成孤兒程序,所以init程序收養了子程序,所以子程序的父程序程序id變成了1。

演示並說明殭屍程序的出現,並演示殭屍程序的危害:

<?php 

$pid = pcntl_fork();

if( $pid > 0 ) else if( 0 == $pid ) else

執行結果如下圖:

通過執行ps -aux命令可以看到,當程式在前十秒內執行的時候,php child process的狀態列為[s+],然而在十秒鐘過後,這個狀態變成了[z+],也就是變成了危害系統的殭屍程序。

那麼,問題來了?如何避免殭屍程序呢?php通過pcntl_wait()和pcntl_waitpid()兩個函式來幫我們解決這個問題。了解linux系統程式設計的應該知道,看名字就知道這其實就是php把c語言中的wait()和waitpid()包裝了一下。

我們將第二個案例中**修改一下:

<?php 

$pid = pcntl_fork();

if( $pid > 0 ) else if( 0 == $pid ) else

將檔案儲存為wait.php,然後php wait.php,在另外乙個終端中通過ps -aux檢視,可以看到在前十秒內,php child process是[s+]狀態,然後十秒鐘過後程序消失了,也就是被父程序**了,沒有變成殭屍程序。

但是,pcntl_wait()有個很大的問題,就是阻塞。父程序只能掛起等待子程序結束或終止,在此期間父程序什麼都不能做,這並不符合多快好省原則,所以pcntl_waitpid()閃亮登場。pcntl_waitpid( $pid, &$status, $option = 0 )的第三個引數如果設定為wnohang,那麼父程序不會阻塞一直等待到有子程序退出或終止,否則將會和pcntl_wait()的表現類似。

修改第三個案例的**,但是,我們並不新增wnohang,演示說明pcntl_waitpid()功能:

<?php 

$pid = pcntl_fork();

if( $pid > 0 ) else if( 0 == $pid ) else

下面是執行結果,乙個執行php程式的終端視窗,另乙個是ps -aux終端視窗。實際上可以看到主程序是被阻塞的,一直到第十秒子程序退出了,父程序不再阻塞:

那麼我們修改第四段**,新增第三個引數wnohang,**如下:

<?php 

$pid = pcntl_fork();

if( $pid > 0 ) else if( 0 == $pid ) else

面是執行結果,乙個執行php程式的終端視窗,另乙個是ps -aux終端視窗。實際上可以看到主程序是被阻塞的,一直到第十秒子程序退出了,父程序不再阻塞:

我們看到子程序是睡眠了十秒鐘,而父程序在執行pcntl_waitpid()之前沒有任何睡眠且本身不再阻塞,所以,主程序自己先執行下去了,而子程序在足足十秒鐘後才結束,程序狀態自然無法得到**。如果我們將**修改一下,就是在主程序的pcntl_waitpid()前睡眠15秒鐘,這樣就可以**子程序了。但是即便這樣修改,細心想的話還是會有個問題,那就是在子程序結束後,在父程序執行pcntl_waitpid()**前,有五秒鐘的時間差,在這個時間差內,php child process也將會是殭屍程序。那麼,pcntl_waitpid()如何正確使用啊?這樣用,看起來畢竟不太科學。

那麼,是時候引入訊號學了!

殭屍程序和孤兒程序

殭屍程序 乙個子程序在其父程序還沒有呼叫wait 或waitpid 的情況下退出。這個子程序就是殭屍程序。孤兒程序 乙個父程序退出,而它的乙個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。孤兒程序將被init程序 程序號為1 所收養,並由init程序對它們完成狀態收集工作。殭屍程序將會導致資源...

殭屍程序和孤兒程序

什麼是殭屍程序?乙個子程序在其父程序沒有呼叫wait 或waitpid 的情況下退出。這個子程序就是殭屍程序。如果其父程序還存在而一直不呼叫wait,則該殭屍程序將無法 等到父程序結束後,會被init 驗證 include include includeint main 3秒後查詢其程序資訊 通過上...

殭屍程序和孤兒程序

殭屍程序和孤兒程序 在unix系統程式設計中,常常會碰到兩個概念 僵死程序和孤兒程序 僵死程序 在unix程序模型中,程序是按照父程序產生子程序,子程序產生子子程序這樣的方式建立出完成各項相互協作功能的程序的。當乙個程序完成它的工作終止之後,它的父程序需要呼叫wait 或者waitpid 系統呼叫取...