LINUX下FORK的執行機制詳細解析

2021-06-19 08:42:29 字數 3426 閱讀 5781

摘要:由於fork函式執行機制的複雜性,造就了當兩個fork併排時,問題就變得很複雜。解這個題的關鍵,一是要對linux下程序的機制有一定認識,二是抓住上文提到的幾個關於fork的關鍵點。

今天一位朋友去乙個不錯的外企面試linux開發職位,面試官出了乙個如下的題目:

給出如下c程式,在linux下使用gcc編譯:

[cpp]view plain

copy

print?

#include "stdio.h"

#include "sys/types.h"

#include "unistd.h"

intmain()    

要求如下:

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

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

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

明顯這道題的目的是考察linux下fork的執行機制。下面我們通過分析這個題目,談談linux下fork的執行機制。

預備知識

這裡先列出一些必要的預備知識,對linux下程序機制比較熟悉的朋友可以略過。

1、程序可以看做程式的一次執行過程。在linux下,每個程序有唯一的pid標識程序。pid是乙個從1到32768的正整數,其中1一般是特殊程序init,其它程序從2開始依次編號。當用完32768後,從2重新開始。

2、linux中有乙個叫程序表的結構用來儲存當前正在執行的程序。可以使用「ps aux」命令檢視所有正在執行的程序。

3、程序在linux中呈樹狀結構,init為根節點,其它程序均有父程序,某程序的父程序就是啟動這個程序的程序,這個程序叫做父程序的子程序。

4、fork的作用是複製乙個與當前程序一樣的程序。新程序的所有資料(變數、環境變數、程式計數器等)數值都和原程序一致,但是是乙個全新的程序,並作為原程序的子程序。

解題的關鍵

有了上面的預備知識,我們再來看看解題的關鍵。我認為,解題的關鍵就是要認識到fork將程式切成兩段。看下圖:

上圖表示乙個含有fork的程式,而fork語句可以看成將程式切為a、b兩個部分。然後整個程式會如下執行:

step1、設由shell直接執行程式,生成了程序p。p執行完part. a的所有**。

step2、當執行到pid = fork();時,p啟動乙個程序q,q是p的子程序,和p是同乙個程式的程序。q繼承p的所有變數、環境變數、程式計數器的當前值。

step3、在p程序中,fork()將q的pid返回給變數pid,並繼續執行part. b的**。

step4、在程序q中,將0賦給pid,並繼續執行part. b的**。

這裡有三個點非常關鍵:

1、p執行了所有程式,而q只執行了part. b,即fork()後面的程式。(這是因為q繼承了p的pc-程式計數器)

2、q繼承了fork()語句執行時當前的環境,而不是程式的初始環境。

3、p中fork()語句啟動子程序q,並將q的pid返回,而q中的fork()語句不啟動新程序,僅將0返回。

解題

下面利用上文闡述的知識進行解題。這裡我把兩個問題放在一起進行分析。

1、從shell中執行此程式,啟動了乙個程序,我們設這個程序為p0,設其pid為***(解題過程不需知道其pid)。

2、當執行到pid1 = fork();時,p0啟動乙個子程序p1,由題目知p1的pid為1001。我們暫且不管p1。

3、p0中的fork返回1001給pid1,繼續執行到pid2 = fork();,此時啟動另乙個新程序,設為p2,由題目知p2的pid為1002。同樣暫且不管p2。

4、p0中的第二個fork返回1002給pid2,繼續執行完後續程式,結束。所以,p0的結果為「pid1:1001, pid2:1002」。

5、再看p2,p2生成時,p0中pid1=1001,所以p2中pid1繼承p0的1001,而作為子程序pid2=0。p2從第二個fork後開始執行,結束後輸出「pid1:1001, pid2:0」。

6、接著看p1,p1中第一條fork返回0給pid1,然後接著執行後面的語句。而後面接著的語句是pid2 = fork();執行到這裡,p1又產生了乙個新程序,設為p3。先不管p3。

7、p1中第二條fork將p3的pid返回給pid2,由預備知識知p3的pid為1003,所以p1的pid2=1003。p1繼續執行後續程式,結束,輸出「pid1:0, pid2:1003」。

8、p3作為p1的子程序,繼承p1中pid1=0,並且第二條fork將0返回給pid2,所以p3最後輸出「pid1:0, pid2:0」。

9、至此,整個執行過程完畢。

所得答案:

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

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

pid1:1001, pid2:0

pid1:0, pid2:1003

pid1:0, pid2:0

進一步可以給出乙個以p0為根的程序樹:

驗證

下面我們去linux下實際執行這個程式,來驗證我們的答案。

程式如下圖:

用gcc編譯、執行後結果如下:

由於我們不太可能剛巧碰上pid分配到1001的情況,所以具體數值可能和答案有所差別。不過將這裡的2710看做基數的話,結果和我們上面的解答是一致的。

總結

應該說這不是一道特別難或特別刁鑽的題目,但是由於fork函式執行機制的複雜性,造就了當兩個fork併排時,問題就變得很複雜。解這個題的關鍵,一是要對linux下程序的機制有一定認識,二是抓住上文提到的幾個關於fork的關鍵點。朋友說,這個題給的時間是5分鐘,應該說時間還算充裕,但是在面試的場合下,還是很考驗乙個人對程序、fork的掌握程度和現場推理能力。

希望本文能幫助朋友們對fork的執行機制有乙個明晰的認識。

**:我自己的理解:

從圖中可以看出,主線程fork出的執行緒,fork的返回值就是該執行緒的pid,但是對於主線程fork的返回值卻是0。從圖中一目了然的就可以知道另外的3中情況。

1 請教fork執行機制 UNIX環境程式設計學習

先看 書中分析 呼叫f o r k建立乙個新程序。新程序是呼叫程序的複製品,故稱呼叫程序為父程序,新創 建的程序為子程序。f o r k對父程序返回新子程序的非負程序i d,對子程序則返回0。因為f o r k創 建一新程序,所以說它被呼叫一次 由父程序 但返回兩次 在父程序中和在子程序中 但是測試...

session執行機制

session機制是一種伺服器端的機制,伺服器使用一種類似於雜湊表 的結構 也可能就是使用 雜湊表 來儲存資訊。當程式需要為某個客戶端的請求建立乙個session的時候,伺服器首先檢查這個客戶端的請求裡是否已包含了乙個session標識 稱為sessionid,如果已包含乙個sessionid則說明...

try catch finally執行機制

finally的執行 如下的程式所示,注釋中是執行的順序 public class test public static string test finally public static string test1 finally其實是僅在return 語句執行前執行,如果return 乙個函式,那...