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