APUE學習心得 fork函式

2021-06-13 20:04:07 字數 3187 閱讀 1534

學習了一段時間的apue,不得不說確實是本好書,但是我進步很慢,一直很苦惱。某人指點我說應嘗試把自己學到的東西寫出來,這樣會有很大的幫助。所以從今天起嘗試一下,希望能夠堅持。

下面開始吧。

fork 函式可以用來為乙個現有程序建立乙個子程序。用fork 函式建立的子程序是父程序的副本,它會copy乙份父程序所有的資料空間、堆和棧等,但是子程序和父程序並不共享儲存空間,僅共享正文段。下面我們看一下下面的例子。

#include "apue.h"

int glob=6;

char buf="a write to stdout\n";

int main(void)

printf("before fork!\n");

if((pid=fork())<0)

else if(pid==0) // this is child process for pid == 0

else //this is parent process

printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);

exit(0);

}

執行這段程式:

[root@localhost apue]# ./fork 

a write to stdout

before fork!

pid=13848,glob=7,var=89

pid=13847,glob=6,var=88

正如書中所說,fork 的返回值在父程序和子程序中不同。在父程序中,fork 函式返回所建立的子程序的程序號,在子程序中則返回0.之所以要在父程序中返回子程序id是因為在父程序中並沒有一種方法能夠獲得所有子程序的程序id,而在子程序中卻可以始終通過getppid 函式來獲取父程序的id。

在回到程式中可以注意到一下幾點:

1.通過fork 返回的pid 是否為0可以區分父程序和子程序。並且在子程序中修改變數(無論全域性變數或區域性變數)均不會對父程序造成影響,反過來也是。

2.fork 之後是父程序先執行還是子程序先執行是不確定的,取決於核心使用的排程演算法。本例中在父程序中通過sleep(2) 讓父程序睡眠,等待子程序執行完畢。在實際應用中還有諸多其他方式保證父子程序同步。

3.將標準輸出重定位定位到乙個檔案(如temp.out)時,執行結果如下:

[root@localhost apue]# ./fork > temp.out

[root@localhost apue]# cat temp.out

a write to stdout

before fork!

pid=17896,glob=7,var=89

before fork!

pid=17895,glob=6,var=88

通過觀察上面的輸出我們可以看到,write 只輸出了一次, printf 輸出了兩次。想要分析這個現象的原因,就得說說unix 的緩衝機制。眾所周知,unix 的write,read等等操作是不帶緩衝的,因此在fork 之前呼叫write ,終端只輸出一次。但printf 函式在向終端輸出的時候是行緩衝,在向檔案輸出的時候是全緩衝。因此在向終端輸出時,因為printf 的內容以『\n』結尾,因此緩衝區經換行符沖洗變為空,而printf 像檔案輸出時為全緩衝,在printf後其內容依然留在了緩衝區中,在fork 子程序時緩衝區連同其中的資料一同複製到子程序中,最終在程式最後的exit 函式的作用下沖洗緩衝區的副本進行輸出。

所以當把printf 函式裡面內容的『\n』去掉,再次執行程式,便會得到如下結果:

[root@localhost apue]# ./fork

a write to stdout

before fork!pid=4935,glob=7,var=89

before fork!pid=4934,glob=6,var=88

關於這個問題,昨天和同宿舍的人吃飯,他給我出了乙個關於fork 的題目。當時在喝二鍋頭,暈暈的沒搞明白,今天試著回想了一下,然後寫出來了,也放在這裡談論一下吧。

#include"apue.h"

int main()

else

}exit(0);

}

問我應該輸出多少個 『-』 ,答案是8個。確實已經暈了,由於沒答上來,就自罰了一口(真無聊啊我們。。。)。

剛我簡單在紙上畫了畫,終於畫明白了。描述一下我的理解吧,不知道正確不正確。

(1)這個程式最開始只有乙個父程序p0,輸出緩衝區是空的。

(2)在執行了第乙個fork 之後,建立了一p0的子程序p0_1,它的緩衝區是複製的p0的緩衝區,因此也是空的。

(3)在p0和p0_1中分別執行了一次 print ,由於沒有換行符,所以緩衝區並沒有被沖洗,因此現在他們的緩衝區中各有乙個 『-』 。

(4)現在開始執行第二個 fork ,第二個fork 為p0和p0_1分別建立了乙個子程序。p0的第二個子程序為p0_2,其緩衝區複製p0,內包含乙個 『-』;p0_1的子程序為p0_1_1,其緩衝區複製p0_1的緩衝區,因此內包含乙個『-』。截止到目前,四個程序的緩衝區中均包含乙個『-』。

(5)接下來所有程序再一次的執行printf ,向各自的緩衝區在寫進乙個 『-』,因此每個程序的緩衝區中均有2個 『-』。

(6)在 exit 的沖洗下,所有緩衝區的內容輸出到螢幕,得到8個『-』。

對程式稍微做一下修改,把最後一句 exit(0) 改為 _exit(0),程式什麼也不輸出了,考慮到兩者區別,確實驗證了我的想法。

再對程式做一下修改,把其中的printf("-") 改為printf("-\n"),程式會輸出什麼呢?讓我們來分析一下,多了『\n』相當於每次都沖洗了緩衝區,緩衝區中的資料會馬上輸出到終端,因此在執行第乙個fork 的時候,p0和p0_1兩個程序各列印出乙個 『-\n』 ,執行第二個fork 後四個程序再各列印乙個 『-\n』,這樣算下來就一共有六個 『-\n』.並且和用exit或者_exit結束程式都沒關係。

4.關於檔案共享。父程序中的所有檔案描述符也都複製到子程序中,父、子相同開啟檔案描述符共享乙個檔案表項,因此父、子程序共享乙個檔案偏移量。如果父子程序沒有同步操作的話,這種共享檔案偏移量的形式會造成父子程序輸出混在一起。因此fork之後處理檔案描述符一般有兩種情況:

(1)父程序等待子程序完成,比如第乙個例子中用的sleep 等方式。

(2)父子程序執行不同的程式段,比如用if 區分pid是否為0 的那種方式,在不同的程式段中處理不同的檔案描述符。

學習心得 python學習心得

自從來了深圳工作以後,尤其是屢屢面試碰壁以後。發現其實自己的知識面很窄,做筆試題的時候絞盡腦汁還是漏洞百出,並不是不會做,而是出現一大堆不該有的失誤。每次被問道,對資料庫了解嗎?說一大堆看起來很高階的東西 好啊,那我們寫幾個sql語句吧。馬上完蛋了,沒了手冊關鍵字都記不起。了解哪幾種指令碼語言,sh...

學習心得 我的學習心得

我是乙個已經步入中年的70後,離開校園已經20年了,因為當年的政策因素而未能圓我的大學夢,在20年的工作過程中總是因為缺少一張大學文憑而失去了很多機會,曾經也考慮過自考,但是乙個人去面對的時候總感覺心有餘而力不足。2018年3月份偶然讓我認識了尚德,原來自考還可以這樣學習。一直懷疑自己年紀大了記憶力...

python函式學習心得

使用函式的好處 1.程式結構清晰,可讀性好。2.減少重複編碼的工作量。3.可多人共同編制乙個大程式,縮短程式設計週期,提高程式設計和除錯的效率。如def print info print print 人生苦短,我用python print print into 1.從使用者的使用角度 庫函式 由系統...