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