C++伺服器:關於兩次fork
我覺得這裡還有些重要的東西沒講,比如setsid()(參見apne 8-11.).
兩次fork()的作用
首先,要了解什麼叫殭屍程序,什麼叫孤兒程序,以及伺服器程序執行所需要的一些條件。兩次fork()就是為了解決這些相關的問題而出現的一種程式設計方法。
孤兒程序
孤兒程序是指父程序在子程序結束之前死亡(return 或exit)。如下圖1所示:
在一定時間內,當系統發現孤兒程序時,init程序就收養孤兒程序,成為它的父親,child程序exit後的資源回收就都由init程序來完成。
殭屍程序
殭屍程序是指子程序在父程序之前結束了,但是父程序沒有用wait或waitpid回收子程序。
父程序沒有用wait回收子程序並不說明它不會回收子程序。子程序在結束的時候會給其父程序傳送一個SIGCHILD訊號,父程序預設是忽略SIGCHILD訊號的,如果父程序通過signal()函式設定了SIGCHILD的訊號處理函式,則在訊號處理函式中可以回收子程序的資源。
事實上,即便是父程序沒有設定SIGCHILD的訊號處理函式,也沒有關係,因為在父程序結束之前,子程序可以一直保持殭屍狀態,當父程序結束後,init程序就會負責回收殭屍子程序。
但是,如果父程序是一個伺服器程序,一直迴圈著不退出,那子程序就會一直保持著殭屍狀態。雖然殭屍程序不會佔用任何記憶體資源,但是過多的殭屍程序總還是會影響系統性能的。黔驢技窮的情況下,該怎麼辦呢?
這個時候就需要一個英雄來拯救整個世界,它就是兩次fork()技法。
兩次fork()技法
如上圖3所示,為了避免子程序child成為殭屍程序,我們可以人為地建立一個子程序child1,再讓child1成為工作子程序child2的父程序,child2出生後child1退出,這個時候child2相當於是child1產生的孤兒程序,這個孤兒程序由系統程序init回收。這樣,當child2退出的時候,init就會回收child2的資源,child2就不會成為孤魂野鬼禍國殃民了。
<unix環境高階程式設計>這本書裡提供了兩次fork的一個例子,程式碼如下:
[cpp] view plaincopy
int main(void)
{
pid_t pid;
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0)
{ /* first child */
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0)
exit(0); /* parent from second fork == first child */
/* We're the second child; our parent becomes init as soon
as our real parent calls exit() in the statement above.
Here's where we'd continue executing, knowing that when
we're done, init will reap our status. */
sleep(2);
printf("second child, parent pid = %d\n", getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
err_sys("waitpid error");
/* We're the parent (the original process); we continue executing,
knowing that we're not the parent of the second child. */
exit(0);
}
理所當然,第二個子程序的父程序是程序號為1的init程序。
一言以蔽之,兩次fork()是人為地建立一個工作子程序的父程序,然後讓這個人為父程序退出,之後工作子程序就由init回收,避免了工作子程序成為殭屍程序。
轉載地址:http://www.cnblogs.com/xiaouisme/archive/2012/07/30/2614547.html