理解fork 的一次呼叫兩次執行

2021-06-16 11:01:48 字數 1615 閱讀 1536

fork()函式是linux裡多程序程式設計的基礎,為linux成為強大的多使用者作業系統提供了強有力的支援。

但是對於很多初學者而言,雖然知道怎麼寫多程序的程式,知道怎麼fork()出乙個子程序,卻很少有人能夠理解fork()的最有特點的乙個性質:一次呼叫,兩次執行。

程序在記憶體裡有三部分的資料——**段、堆疊段和資料段。這三個部分是構成乙個完整的執行序列的必要的部分。

**段——存放了程式**的記憶體空間。這個最容易理解,不就是程式在機器內的表示而已嘛。注意假如機器中有數個程序執行相同的乙個程式,那麼它們就可以使用相同的**段。也就是說如果fork()出來了乙個子程序,子程序和父程序實際上使用的是相同的**段。

int a;

void main()

int func()

這個程式裡哪些變數是存放在堆疊段裡的呢?不考慮編譯器優化,實際上變數b,c,d都是會存放在堆疊裡的。而a則會存放在接下來說的資料段裡。

資料段——存放程式的全域性變數,常數以及動態資料分配的資料空間(比如用malloc之類的函式取得的空間)。

好了,知道了上面三個段之後有什麼用呢?用處可大了,這就說明了系統中的每乙個程序都需要由這三個段來組成。不管是父程序還是fork()出來的子程序。但是上面也提到,由於子程序和父程序執行的是同樣的程式(只是程式裡的不同部分),它們使用相同的**段,但是會擁有各自的資料段和堆疊段。

我們通常會這樣寫乙個程式:

void main()

else if(pid>0)

}

執行過程是這樣的:

1.作業系統分配記憶體給父程序,包括上面提到的三個段,就是會在堆疊段裡有一塊空間是用來存放pid變數的。

2.接著核心排程父程序執行fork()函式(這個函式裡實際上使用了系統呼叫),這時候子程序才會出現,核心會將父程序的資料段和堆疊段作乙個拷貝給子程序,注意這時子程序的堆疊段裡一定會有乙個空間用來存放pid變數!然後系統呼叫成功,核心給父程序堆疊段裡的pid變數賦上子程序的pid號,而給子程序堆疊段裡的pid變數賦上0。

3.接下來還是交給核心排程決定執行的是子程序還是父程序(一般核心會先給子程序執行)。如果是父程序,它的下一句**就是判斷pid變數的大小,它會去它的堆疊段裡存放pid變數的地方取出pid來進行比較,它會發現pid>0,所以接下來它就去執行——父程序任務;如果是子程序,由於同樣的**段,它也會去比較它自己的pid變數,發現pid=0,所以接下來它會去執行——子程序任務。

注:左邊父程序,右邊子程序

這樣,fork()函式就實現了一次呼叫,兩次執行。關鍵就是在於父子程序擁有不同的堆疊段,而核心給這兩個堆疊段裡的pid賦上不同的值。

最後,我們來看看編譯後的匯程式設計序,就能證實我的說法,也能更好地理解。

esp是堆疊指標暫存器,可以看到,在呼叫fork()函式之後將28(%esp)和0進行了比較,顯然,28(%esp)就是pid變數。它存放在堆疊段裡。

一次fork與兩次fork的區別

在講一次fork和兩次fork之前,有必要先來簡單講解一下wait的作用 1 阻塞當前程序 2 獲得子程序退出的相關資訊 殭屍程序 子程序不返回,父程序後邊的內容就沒法執行。注 wait函式只能在有子程序的父程序中呼叫。我們使用fork 函式建立乙個子程序出來往往是為了父子程序能夠同時執行兩段 如果...

關於兩次fork

兩次fork 的作用 首先,要了解什麼叫殭屍程序,什麼叫孤兒程序,以及伺服器程序執行所需要的一些條件。兩次fork 就是為了解決這些相關的問題而出現的一種程式設計方法。孤兒程序 孤兒程序是指父程序在子程序結束之前死亡 return 或exit 如下圖1所示 在一定時間內,當系統發現孤兒程序時,ini...

關於兩次fork

兩次fork 的作用 首先,要了解什麼叫殭屍程序,什麼叫孤兒程序,以及伺服器程序執行所需要的一些條件。兩次fork 就是為了解決這些相關的問題而出現的一種程式設計方法。孤兒程序 孤兒程序是指父程序在子程序結束之前死亡 return 或exit 如下圖1所示 在一定時間內,當系統發現孤兒程序時,ini...