乙個現有的程序可以通過兩種方式建立乙個新的程序,下面詳細介紹兩種函式原型( man 手冊):fork()
、vfork()
。
#include
pid_t fork(void);
描述:fork()
以當前的程序為副本建立乙個新的程序,新建立的程序被稱為子程序, 當前的程序被稱為父程序,父程序和子程序執行在各自的位址空間。
返回值:
在父程序中返回子程序 的pid,子程序中返回0。可以這樣理解,對於父程序來說它可以有多個子程序,所以父程序需要知道子程序的 pid , 而對於子程序來說,它只有乙個父親,而且其父程序 ppid 已經記錄在它的pcb
中了,所以就沒必要再返回父程序 pid 了。而fork失敗的話返回-1。
fork失敗原因:
用法例項:#include
#include
#include
#include
#include
int main()
else
if(ret > 0)else
printf("%d come here\n", getpid());
return
0;
}
執行結果:
從**中看,我們讓父程序睡眠三秒(三秒並不保證子程序能執行完),以保證讓子程序先執行,3 秒後父程序開始執行,列印結果如我們所料。
下面看看系統呼叫 fork 的原理。
在執行fork
函式後,核心將拷貝乙份父程序的副本作為子程序。子程序獲得父程序的資料空間,堆和棧、檔案描述符表(這通常在網路服務中使用,即父子程序各自關閉自己不需要的檔案描述,這樣就不會對對方造成影響)…的副本,但是父子程序共享正文段,即**段。所以fork
之後,父子程序仍然執行的是同乙份**,但我們根據返回值得不同,可以讓它們執行不同的邏輯,如上圖所示,在fork
之後父子程序各自執行灰色部分**,從上面執行結果中也可以看出 (注意!這只是讓它們執行不同的邏輯,本質上執行的還是同乙份**)
一般情況下,被建立的子程序會呼叫程序替換函式exec
,所以fork
之後子程序一般就不去執行和父程序同樣的**。
父子程序除了共享**段之外,它們也共享資料段。父子程序的資料段通過頁表對映到同一塊物理記憶體中,當有一方企圖修改資料段時,便以寫時拷貝的方式 —— 先拷貝乙份要修改的資料,再通過頁表對映到新拷貝的記憶體處,這樣一方對資料的修改就不會影響另一方。如下例項:
#include
#include
#include
#include
#include
int g_val = 0;
int main()
else
if(ret > 0)else
printf("%d come here\n", getpid());
return
0;
}
執行結果:
可以看到,父子程序對資料的修改並不會影響到對方。如下圖:
vfork
函式也用來建立乙個程序,但不同於fork
的是vfork
出的子程序不會獲得乙份父程序的副本,而是直接在父程序的位址空間內執行,所以子程序對資料的修改會影響到父程序內。這一點將在下面驗證。這麼做的原因是:建立的子程序會立即呼叫exec
程序函式替換,所以子程序不會使用父程序的位址空間。
除此之外,vfork
函式會保證子程序先執行,直到子程序呼叫exit
或exec
函式後,父程序才會被排程執行,此間,父程序一直被掛起等待子程序的執行結束。如下**:
可以看到,子程序執行完了,父程序才執行,而且子程序中對變數i
的修改影響到了父程序。
——完!
程序建立函式fork與vfork
1.fork 1 函式的功能 建立乙個程序 2 函式的原型 pid t fork void 3 函式的返回值 0 出錯 0 子程序 0 父程序 其值為子程序的識別號 4 標頭檔案 include fork的奇妙之處在於它被呼叫一次,卻返回兩次,它可能有三種不同的返回值。include include...
程序建立之fork與vfork
由圖中的對映關係我們可以發現,虛擬位址與實體地址並不是一一對應的,這樣也就會出現一種問題,乙個變數位址相同內容不同,其實是虛擬位址相同,所對應的實體地址不同的原因 那麼是誰管理著虛擬位址空間呢?pcb中有mm strct管理虛擬位址空間 linux中絕大多數函式出錯返回值都是 1,函式出錯後將錯誤編...
程序的建立 fork與vfork
目錄 fork函式 fork的使用 vfork函式 fork 與 vfock 都是建立乙個程序,那它們有什麼區別呢?程序的正常終止方法?程序的異常終止 為什麼vfork 子程序中可以呼叫 exit 卻不可以呼叫exit 也不可以直接return呢?標頭檔案 include 函式原型 pid t fo...