天天看點

關于fork函數的使用問題

在oldlinux論壇中,有一則文章,題目也是“關于fork函數的使用問題”,樓主提出了一個很有意思的問題:

在linux0.11下寫了一個程式,大家看一下,應該是什麼結果 #include #include main() { int pid,i; for (i=0;i<2;i++){ pid=fork(); if(pid==0) printf(“child=%d\n”,i); else printf(“parent=%d\n”,i); } }

而在2樓,樓主給出了列印結果:

我運作後的結果

parent=0

parent=1

child=1

child=0

parent=1

child=1

為什麼會列印出三個parent,三個child呢?

對于列印情況,3樓給出了一個合理的解釋:

i=0: fork之後産生兩個程序,分别列印“XXX=0”

i=1: 上面的兩個程序又fork,這時4個程序了,再分别列印“XXX=1”

是以一共列印6句話,2句列印0,4句列印1

這個解釋雖然合理,但是不夠詳盡,是以容易造成一知半解。而且,無法充分解釋列印順序。

我在這裡給出一個更詳盡的解釋:

首先,有幾個前提需要指明:

1. fork()函數隻是建立了目前程序的子程序,傳回值為子程序的pid。而且并不會立即調用子程序。

2. fork()函數建立了子程序後,子程序儲存的是進入建立程序時的父程序的運作環境。換句話說,子程序被建立後第一次運作時,是從fork()指令在機器碼程式中的下一條指令開始執行的。在目前我們讨論的程式中,子程式是從

if(pid==0)

這一個指令開始執行。而且,子程序在建立後的傳回值總是0,是以子程序一定會運作

printf("child=%d\n",i);

3. 目前我從Linux 0.11版本中了解的程序排程前提有如下幾個:

1) 定時器中斷造成程序排程

2) 目前程序運作結束後造成程序排程

3) 目前程序挂起後造成程序排程

4. 程序排程的邏輯如下:目前程序不為就緒态,或者目前程序在就緒态但是剩餘運作時間不是最大值,就會運作另一個程序,否則,會運作目前程序。

那我們再來看文章中樓主給出的程式主體部分:

for(i=0;i<2;i++) {
    pid=fork();
    if(pid==0) printf("child=%d\n",i);
    else printf("parent=%d\n",i);
}
           

我們把這個循環展開,可以有如下代碼段2:

1: i=0;
 2: pid=fork();
 3: if(pid==0) 
 4:     printf("child=%d\n",i);
 5: else 
 6:     printf("parent=%d\n",i);
 7: i=1;
 8: pid=fork();
 9: if(pid==0) 
10:     printf("child=%d\n",i);
11: else 
12:     printf("parent=%d\n",i);
13: //目前程序結束
           

在詳細解釋之前,我們先假設運作這段代碼的程序的pid為1。根據展開後的代碼有如下分析。

1. 程序1運作到第2行時,就會通過fork()建立一個子程序,其pid為2。fork()的傳回值也就是2。這時并不會立即調用程序2。

2. 程序1繼續運作到第3行,判斷到傳回值不為0,則運作第6行,列印

parent=0

3. 程序1繼續運作到第8行,又會通過fork()建立一個子程序,其pid為3。fork()的傳回值也就是3。同樣這裡并不會立即調用程序3。

4. 程序1繼續運作到第9行,判斷到傳回值不為0,則運作第12行,列印

parent=1

5. 程序1結束。此時會觸發前提3中的程序排程。這時,候補程序有2個,pid分别為2和3。需要注意的是,程序3建立時間晚于程序2,那麼它的剩餘時間就大于程序2,是以會先調用程序3。根據前提2中的描述,我們得知程序3從第9行開始運作,其傳回值為0,則運作第10行,列印

child=1

6. 程序3結束。此時會再次觸發程序排程。這時隻有程序2在等待,那麼就調用程序2。由于程序2是在第2行中建立的,是以調用時就從第3行開始執行,傳回值為0,繼續運作第4行,列印

child=0

7. 程序2繼續執行,到第8行時,程序2會通過fork()建立一個子程序,如果之前死去的程序3并未被完全釋放,那麼pid會是4。

8. 程序2執行到第9行,判斷傳回值為4,那麼執行第12行,列印

parent=1

9. 進行2結束。然後繼續出發程序排程,此時進行4在等待,那麼調用程序4。從第9行開始執行,其傳回值為0,則運作第10行,列印

child=1

這裡讨論的結果并未涉及到定時器中斷導緻的程序排程。如果程式運作時剛好遇到定時器中斷,那麼列印結果肯定是另一種。這要根據定時器中斷觸發的位置來進行分析。

剛好又看到一篇類似的面試題,連結如下:http://www.cnblogs.com/vanishfan/archive/2012/11/01/2750157.html

文章中的問題在我讨論的基礎上又加入了塊裝置的輸出問題。

繼續閱讀