Linux下,當需要創建進程時,我們最常使用的就是fork()函數,但你真的瞭解它嗎?
簡略複習
我們先來複習一下fork的運行規則,詳細請參見Linux:認識進程:
功能:以父進程爲模板,創建子進程
1.會把父進程的PCB拷貝一份,部分會修改,成爲子進程的PCB
2.會把父進程的虛擬地址空間拷貝一份,作爲子進程的地址空間。
- 寫時拷貝,父子進程公用一份代碼,各有一份數據(極端情況下代碼段也會發生拷貝)
- 由於大部分的內存空間可能被拷貝,創建進程的開銷仍然比較高(和線程比)
3.fork 返回在父子進程中分別返回;
- 成功:父進程中返回子進程的pid ;子進程返回0;父子進程在fork後面繼續往下執行。
- 失敗:返回-1:原因主要是內存不夠或進程太多達到上限;
4.父子進程執行順序沒有先後關係,全靠調度器實現.
牛刀小試
在簡略地複習過後,我們就來檢測一番吧:
求程序運行結果
#include<stdio.h>
#include<usistd.h>
int main(){
for(int i = 0;i<2;i++){
fork();
printf("=");
}
return 0;
}
結果是"========"是你所期望的嗎
- 乍一看,主程序申請了兩個子程序,但你需要注意的是,子程序在運行時,也會運行fork();,我們來畫圖表達這一過程:
我們看到,當i=0時,創建一個子進程,並分別向各自緩衝區寫入一個=,當i=1時,這兩個進程又分別創建子進程,這些新的子進程將父進程緩衝區裏的=也都各自拷貝了過來,然後這四個進程都執行printf("=");至此每個進程的緩衝區都有兩個=,然後都return 0 結束函數並刷新緩衝區,打印到屏幕上的=一共有8個;
#include<stdio.h>
#include<usistd.h>
int main(){
for(int i = 0;i<2;i++){
fork();
printf("=");
fflush(stdout);
}
return 0;
}
結果是"======",我們來看看具體過程
這裏由於每次打印=後立即刷新緩衝區打印到屏幕上,這使得i=1時兩個進程fork子進程時並沒有拷貝=過去,然後四個進程各自輸出一個=到屏幕上,加上之前兩個共打印了6個;
這兩道題更加印證了前面所回顧的父子進程公用一份代碼,各有一份數據(極端情況下代碼段也會發生拷貝)