5.fork和vfork
fork和vfork函數(shù)都是用于創(chuàng)建子進程的系統(tǒng)函數(shù)。
fork函數(shù)調(diào)用一次,返回兩次。兩次返回的返回值不同。
1)返回值等于0時,處于子進程空間。
理由:一個進程只會有一個父進程,所以子進程總是可以調(diào)用getppid()來獲得父進程的進程ID(進程ID為0的進程為系統(tǒng)的內(nèi)核交換進程,所以一個子進程的進程ID不可能為0)
2)返回值為正值(也即子進程pid)時,處于父進程空間。
理由:一個父進程可以創(chuàng)建多個子進程,并且也沒有一個函數(shù)能夠返回父進程的所有子進程ID。通過返回子進程的進程ID給父進程,有助于父進程記錄子進程的相關信息。
?
fork()過程
父進程調(diào)用fork(),并從內(nèi)存為此進程分配一個新的可用的進程標識符。之后,為這個進程分配進程空間,并將父進程進程空間中的數(shù)據(jù)段、堆棧段復制到子進程的進程空間之中。父子進程共享代碼段,此時子進程和父進程一模一樣。父子進程之間的執(zhí)行順序是不確定的,取決于內(nèi)核的調(diào)度算法。由于子進程復制了父進程的堆棧段,因此兩個進程都停留在了fork函數(shù)中,等待返回。因此fork函數(shù)調(diào)用一次,返回兩次。
我們知道在調(diào)用fork()函數(shù)之后,常常會接著調(diào)用exec()函數(shù)。子進程會復制父進程的地址空間(數(shù)據(jù)段,堆棧),父子進程共享正文段(也即是代碼段),盡管有寫時復制技術,但是還是不可避免的會進行內(nèi)存空間的復制。而后面我們要提到的vfork函數(shù)會直接使得子進程依附在父進程空間執(zhí)行,只是子進程優(yōu)先于父進程執(zhí)行!
一般來說,fork之后父子進程之間的執(zhí)行順序是不確定的,取決于內(nèi)核的調(diào)度算法。
fork函數(shù)與I/O函數(shù)之間具有一定的交互關系。比如在fork子進程之前,我們調(diào)用write函數(shù)輸出一行內(nèi)容,由于write函數(shù)是不帶緩沖的,所以將其數(shù)據(jù)寫到標準輸出一次。標準I/O是帶有緩沖的。我們知道,當標準輸出連接到終端設備的時候,它是行緩沖的,其它的則是全緩沖的。由于標準輸出緩沖區(qū)是以換行符來沖洗,因此當我們以交互式的方式運行該程序的時候。只得到該printf輸出一次。而當我們將標準輸出重定向到一個文件的時候,卻可以得到兩次輸出行。其原因是子進程復制了父進程的數(shù)據(jù)空間,該緩沖區(qū)也被復制進子進程中,此時父子進程都擁有該行內(nèi)容的緩沖區(qū)。具體看APUE(184)
記得,父進程的標準輸出被重定向之后,子進程的標準輸出也會被重定向的。很簡單,其實fork的一個特性就是:父進程所有打開的文件描述符都會被復制到子進程之中。父子進程之間共享一個文件表項。
fork之后,處理文件描述符有兩種情況:
1)父進程等待子進程完成。子進程讀寫操作完之后,更新文件描述符的文件偏移量。
2)父子進程各自執(zhí)行不同的代碼段。父子進程各自關閉自己不需要的文件描述符,這樣就不會對對方產(chǎn)生影響。網(wǎng)絡服務器程序就是這種處理方式。
fork一般有兩種用法:
1)一個父進程希望復制自己,使父進程和子進程執(zhí)行不同的代碼段。例如:在服務器程序中,父進程用于監(jiān)聽外來連接,一旦請求介入,父進程就fork出子進程處理連接。
2)各自執(zhí)行不同的程序。這在這種情況下,fork返回后立即調(diào)用exec函數(shù)。
vfork和fork的調(diào)用序列、返回值都是相同的。只是,vfork函數(shù)用于創(chuàng)建一個子進程,而這個子進程的目的是來exec一個新的程序。vfork創(chuàng)建的子進程在調(diào)用exec或者exit之前都在父進程空間執(zhí)行。能夠大大提高UNIX系統(tǒng)的實現(xiàn)效率。
vfork和fork另一個區(qū)別就是:vfork優(yōu)先執(zhí)行子進程!!!在它調(diào)用exec或者exit之后父進程才可能被調(diào)用。
但有一點缺點,如果子進程調(diào)用這兩個函數(shù)的操作依賴于父進程的進一步操作,則會導致死鎖的發(fā)生!
總結(jié)
以上是生活随笔為你收集整理的5.fork和vfork的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 剑指offer:写一个函数,求两个整数之
- 下一篇: 6.exit _exit _