乙個很有趣的fork面試程式,和大家分享下經驗

2021-09-19 23:24:47 字數 2616 閱讀 1734

大家有興趣可以想想,下面輸出了多少個「g」?

#include #include #include int main(void)

wait(null);

wait(null);

return 0;

}

也許你很快就說,那麼簡單,第一次迴圈,fork後2個程序,第二次再fork出4個,一共6個程序,肯定是6個「g」

恭喜你,如果我是面試官,那麼你已經跪了 = =

答案:會輸出8個「g」

有乙個很重要的東西是,在fork()的呼叫處,整個父程序空間會原模原樣地複製到子程序中,包括指令,變數值,程式呼叫棧,環境變數,緩衝區,等等。

等等!!什麼,你說全部複製過去?那麼我可以解釋為:

上面的那個程式為什麼會輸入8個「-」,這是因為printf(「-「);語句有buffer

我們來試試printf的緩衝區:

#include #include //for sleep()

int main(void)

return 1;

}

哦哦!!如果不做fflush這個動作,上邊的輸出便不會顯示到螢幕上咯?

除非其中有換行操作或者緩衝區,這也許就是所謂的「到終端行規程」!

呃呃,不要脫離了重點,我們還是回到剛才的fork問題上~

既然我們知道了printf有緩衝區,那麼,又如何?

容我引用下酷殼大神美麗的**:

你可以清楚的看到,用陰影框標註出來的兩個「最終版子程序(i=2)」

他們在fork拷貝的時候,就將 parent的緩衝區一併拷貝過去,這時「g」還在緩衝區

那麼,在輸出的時候,兩個子程序才一併把「g」從緩衝區輸出來,那麼是不是兩個子程序沒人多輸出了乙個?

1+1+1+1+12+12=8個

ok,我知道你和我一樣可能有點懵懵的,我改下程式咯~

#include #include #include int main(void)

wait(null);

wait(null);

return 0;

你可以gcc下這個程式,在我的電腦裡輸出是這樣的:

g  ppid=3082, pid=3128, i=0 g  ppid=3128, pid=3130, i=1 

g ppid=3128, pid=3129, i=0 g ppid=3129, pid=3131, i=1

g ppid=3128, pid=3129, i=0 g ppid=3128, pid=3129, i=1

g ppid=3082, pid=3128, i=0 g ppid=3082, pid=3128, i=1

可以看到ppid為3082 pid為3128的輸出有3次

同樣的,ppid為3128 pid為3129的輸出有3次

你將顯然發現,原本i=0時應該只會有兩個「g」被輸出,但是現在居然詭異地多出了兩個?到底是哪兩個呢?

我索性標註下這個輸出結果吧~

(1)g  ppid=3082, pid=3128, i=0 (5)g  ppid=3128, pid=3130, i=1 

(2)g ppid=3128, pid=3129, i=0 (6)g ppid=3129, pid=3131, i=1

(3)g ppid=3128, pid=3129, i=0 (7)g ppid=3128, pid=3129, i=1

(4)g ppid=3082, pid=3128, i=0 (8)g ppid=3082, pid=3128, i=1

明顯的,(1)和(4)是「不可能」有兩個的,(2)和(3)也是,現在你知道了吧,i=0時的兩個程序,在下一次fork的時候各自成為了下乙個父程序,在這一次fork時,他們的資訊被完全複製到了子程序,那麼最後一步每乙個子程序緩衝區裡還存有多餘的「g」(見上圖)

你還可以用pstree -p | grep fork命令試下

可以得出乙個樹狀的結構:

$ pstree -p | grep fork

|-bash(3082)-+-fork(3128)-+-fork(3129)---fork(3131)

| | `-fork(3130)

那麼,最後我們再試試,在printf乙個g的後面加上乙個換行符(或者fflush)

#include #include #include int main(void)

wait(null);

wait(null);

return 0;

}

輸出的結果將是換行的6個「g

原因就在於,每一次換行,緩衝區的「g」,就會把資料「刷」出緩衝區

(其實或是eof,或是緩中區滿,或是檔案描述符關閉,或是主動flush,或是程式退出)

yield 乙個很有趣的關鍵字

在偶然的機會下發現了這個關鍵字yield,它的作用是在乙個迴圈體 例如 foreach,for 內部 與return 一起做輸出.要注意的是yield return 所在函式的返回值為ienumerable介面型別 下面實現的是從一堆資料中找出大於特定數字的結果集。namespace test fo...

防止可重入 乙個有趣的類和乙個很有用的巨集!

這幾天在研究todolist 原始碼,看到一簡短的類,很很有意思,現把原始碼列下,並附上簡短說明 注 重入即表示重複進入,首先它意味著這個函式可以被中斷,其次意味著它除了使用自己棧上的變數以外不依賴於任何環境 包括static 這樣的函式就是 purecode 純 可重入,可以允許有該函式的多個副本...

乙個fork的面試題

題目 請問下面的程式一共輸出多少個 include inlcude int main return 0 可能開始的時候大家都以為會輸出6個 但是結果輸出了8個 要弄明白這個題,還是先從fork 呼叫開始 1 fork 系統呼叫是unix下以自身程序建立子程序的系統呼叫,一次呼叫,兩次返回,如果返回時...