首先,要了解什么叫僵尸進(jìn)程,什么叫孤兒進(jìn)程,以及服務(wù)器進(jìn)程運(yùn)行所需要的一些條件。兩次fork()就是為了解決這些相關(guān)的問題而出現(xiàn)的一種編程方法。
孤兒進(jìn)程
孤兒進(jìn)程是指父進(jìn)程在子進(jìn)程結(jié)束之前死亡(return 或exit)。如下圖所示:
但是孤兒進(jìn)程并不會像上面畫的那樣持續(xù)很長時間,當(dāng)系統(tǒng)發(fā)現(xiàn)孤兒進(jìn)程時,init進(jìn)程就收養(yǎng)孤兒進(jìn)程,成為它的父親,child進(jìn)程exit后的資源回收就都由init進(jìn)程來完成。
僵尸進(jìn)程
僵尸進(jìn)程是指子進(jìn)程在父進(jìn)程之前結(jié)束了,但是父進(jìn)程沒有用wait或waitpid回收子進(jìn)程。如下圖所示:
父進(jìn)程沒有用wait回收子進(jìn)程并不說明它不會回收子進(jìn)程。子進(jìn)程在結(jié)束的時候會給其父進(jìn)程發(fā)送一個SIGCHILD信號,父進(jìn)程默認(rèn)是忽略SIGCHILD信號的,如果父進(jìn)程通過signal()函數(shù)設(shè)置了SIGCHILD的信號處理函數(shù),則在信號處理函數(shù)中可以回收子進(jìn)程的資源。
事實上,即便是父進(jìn)程沒有設(shè)置SIGCHILD的信號處理函數(shù),也沒有關(guān)系,因為在父進(jìn)程結(jié)束之前,子進(jìn)程可以一直保持僵尸狀態(tài),當(dāng)父進(jìn)程結(jié)束后,init進(jìn)程就會負(fù)責(zé)回收僵尸子進(jìn)程。
但是,如果父進(jìn)程是一個服務(wù)器進(jìn)程,一直循環(huán)著不退出,那子進(jìn)程就會一直保持著僵尸狀態(tài)。雖然僵尸進(jìn)程不會占用任何內(nèi)存資源,但是過多的僵尸進(jìn)程總還是會影響系統(tǒng)性能的。黔驢技窮的情況下,該怎么辦呢?
這個時候就需要一個英雄來拯救整個世界,它就是兩次fork()技法。
兩次fork()技法
兩次fork()的流程如下所示:
《UNIX環(huán)境高級編程》(下載見http://www.linuxidc.net/thread-2063-1-1.html)這本書里提供了兩次fork的一個例子,代碼如下:
理所當(dāng)然,第二個子進(jìn)程的父進(jìn)程是進(jìn)程號為1的init進(jìn)程。
一言以蔽之,兩次fork()是為了防止系統(tǒng)中產(chǎn)生僵尸進(jìn)程。
參考文獻(xiàn):《UNIX環(huán)境高級編程》下載見http://www.linuxidc.net/thread-2063-1-1.html 與 http://www.linuxidc.com/Linux/2011-04/34662.htm