天天看點

fork函數總結

在unix/linux中用fork函數建立一個新的程序。程序是由目前已有程序調用fork函數建立,分叉的程序叫子程序,建立者叫父程序。該函數的特點是調用一次,傳回兩次,一次是在父程序,一次是在子程序。兩次傳回的差別是子程序的傳回值為0,父程序的傳回值是新子程序的id。子程序與父程序繼續并發運作。如果父程序繼續建立更多的子程序,子程序之間是兄弟關系,同樣子程序也可以建立自己的子程序,這樣可以建立起定義關系的程序之間的一種層次關系。

  程式包含位于記憶體的多個組成部分,執行程式的過程将根據需要來通路這些内容,包括文本段(text segment)、資料段(data segments)、棧(stack)和堆(heap)。文本段中存放cpu所執行的指令,資料段存放程序操作的所有資料變量,棧存放自動變量和函數資料,堆存放動态記憶體配置設定情況資料。當程序被建立時,子程序收到父程序的資料副本,包括資料空間、堆、棧和程序描述符。

程式1:建立一個子程序,子程序對繼承的資料進行修改,然後分别輸出父子程序的資訊。程式如下:

fork函數總結
fork函數總結
fork函數總結

fork函數執行後程式結構圖如下:

fork函數總結

子程序與父程序并行執行,是以在父程序中sleep(10),讓子程序先執行,然後再執行父程序。

程式執行結果如下所示:

fork函數總結

如何建立多個子程序呢?在開發并發伺服器時,用到的程序池模型需要先建立指定書目的子程序。舉個例子,假如我們現在需要建立2個子程序,很容易想到的是調用一個循環,執行fork函數2次即可。嘗試一下是否可行呢?代碼如下:

fork函數總結
fork函數總結
fork函數總結

程式執行結果如下:

fork函數總結

從結果來看,子程序的數目不是2而是3,這是為什麼呢?先簡單的分析一下:從結果看出父程序id為10669,子程序的id分别為:10670、10671、10672。

父子程序之間的關系如下:

fork函數總結

id為10670的子程序也調用fork函數,建立了一個程序。因為fork函數建立的程序是父程序的一份拷貝,儲存了目前的資料空間、堆、棧及共享代碼區域。正确的方式應該是在子程序中跳出,停止繼續fork。改進的代碼如下:

fork函數總結
fork函數總結
fork函數總結
fork函數總結

 從結果可以看出這父程序(id為10789)建立了兩個子程序(id分别為:10790、10791)。

現有有這樣一個面試題,程式如下:

fork函數總結
fork函數總結

要求如下:

 已知從這個程式執行到這個程式的所有程序結束這個時間段内,沒有其它新程序執行。

 1、請說出執行這個程式後,将一共運作幾個程序。

 2、如果其中一個程序的輸出結果是“pid1:1001, pid2:1002”,寫出其他程序的輸出結果(不考慮程序執行順序)。

  這個題目考查fork函數的了解。fork的作用是複制一個與目前程序一樣的程序。新程序的所有資料(變量、環境變量、程式計數器等)數值都和原程序一緻,但是是一個全新的程序,并作為原程序的子程序,父子程序并行的執行剩下的部分。

程式的執行過程如下:

(1)程式開始執行時候系統配置設定一個程序進行執行,稱該程序為主程序p,程序id題目未給,

(2)主程序執行到第一個fork函數的時候,建立一個新的子程序p1,有題目可知程序id為1001,fork函數有兩個傳回值,傳回pid=0代表子程序p1,pid1>0代表父程序p。

(3)現在有兩個程序p和p1,分别執行剩下部分,

(4)p程序(父程序,是以pid1=1001)調用fork建立子程序p2,傳回兩個值中pid2=1002表示p2的程序id傳回給父程序p,pid2=0子程序p2本身,是以輸出pid1=1001,         pid2=1002和pid1=1001,pid2=0。

(5)p1程序(子程序,是以pid1=0)調用fork建立子程序p3,程序id類推為1003,傳回兩個值中pid2=1003表示p3的程序id傳回給父程序p1,pid2=0辨別程序p3本身。是以輸出pid1=0,pid2=1003和pid1=0,pid2=0。

(6)執行整個結束。

根據以上分析可知答案:

1、一共執行了四個程序。(p0, p1, p2, p3)

2、另外幾個程序的輸出分别為:

 pid1:1001, pid2:0

 pid1:0, pid2:1003

 pid1:0, pid2:0

上機測試如下:

fork函數總結

測試結果如下:

fork函數總結

測試結果雖然不是1001,但是可以看出理論分析過程是正确的。

繼續閱讀