fork - 計算機(jī)程序設(shè)計中的分叉函數(shù)
fork:叉子、分岔、岔口、復(fù)刻,西方人吃飯用的東西,經(jīng)常用作刀和叉。計算機(jī)程序設(shè)計中的分叉函數(shù)。返回值:若成功調(diào)用一次則返回兩個值,子進(jìn)程返回0,父進(jìn)程返回子進(jìn)程標(biāo)記;否則,出錯返回-1。
中文翻譯
fork:叉子//分岔//岔口//復(fù)刻,西方人吃飯用的東西,經(jīng)常用作刀和叉。
函數(shù)原型
pid_tfork - void;(pid_t是一個宏定義,其實(shí)質(zhì)是int被定義在#include中);返回值:若成功調(diào)用一次則返回兩個值,子進(jìn)程返回0,父進(jìn)程返回子進(jìn)程ID;否則,出錯返回-1。
os.fork:
有兩種方式來實(shí)現(xiàn)并發(fā)性:
1、一種方式是讓每個“任務(wù)"或“進(jìn)程”在單獨(dú)的內(nèi)在空間中工作,每個都有自已的工作內(nèi)存區(qū)域。不過,雖然進(jìn)程可在單獨(dú)的內(nèi)存空間中執(zhí)行,但除非這些進(jìn)程在單獨(dú)的處理器上執(zhí)行,否則,實(shí)際并不是“同時”運(yùn)行的。是由操作系統(tǒng)把處理器的時間片分配給一個進(jìn)程,用完時間片后就需退出處理器等待另一個時間片的到來。
2、另一種方式是在在程序中指定多個“執(zhí)行線程”,讓它們在相同的內(nèi)存空間中工作。這稱為“多線程處理”。線程比進(jìn)程更有效,因?yàn)椴僮飨到y(tǒng)不必為每個線程創(chuàng)建單獨(dú)的內(nèi)存空間。
新建進(jìn)程用os.fork函數(shù)。但它只在POSIX系統(tǒng)上可用,在windows版的python中,os模塊沒有定義os.fork函數(shù)。相反,windows程序員用多線程編程技術(shù)來完成并發(fā)任務(wù)。
os.fork函數(shù)創(chuàng)建進(jìn)程的過程是這樣的。程序每次執(zhí)行時,操作系統(tǒng)都會創(chuàng)建一個新進(jìn)程來運(yùn)行程序指令。進(jìn)程還可調(diào)用os.fork,要求操作系統(tǒng)新建一個進(jìn)程。父進(jìn)程是調(diào)用os.fork函數(shù)的進(jìn)程。父進(jìn)程所創(chuàng)建的進(jìn)程叫子進(jìn)程。每個進(jìn)程都有一個不重復(fù)的進(jìn)程ID號?;蚍Qpid,它對進(jìn)程進(jìn)行標(biāo)識。子進(jìn)程與父進(jìn)程完全相同,子進(jìn)程從父進(jìn)程繼承了多個值的拷貝,如全局變量和環(huán)境變量。兩個進(jìn)程的唯一區(qū)別是fork的返回值。子進(jìn)程接收返回值0,而父進(jìn)程接收子進(jìn)程的pid作為返回值。一個現(xiàn)有進(jìn)程可以調(diào)用fork函數(shù)創(chuàng)建一個新進(jìn)程。
由fork創(chuàng)建的新進(jìn)程被稱為(childprocess)子進(jìn)程。fork函數(shù)被調(diào)用一次但返回兩次。兩次返回的唯一區(qū)別是子進(jìn)程中返回0值而父進(jìn)程中返回子進(jìn)程ID。對于程序,只要判斷fork的返回值,就知道自己是處于父進(jìn)程還是子進(jìn)程中。
子進(jìn)程是父進(jìn)程的副本,它將獲得父進(jìn)程數(shù)據(jù)空間、堆、棧等資源的副本。注意,子進(jìn)程持有的是上述存儲空間的“副本”,這意味著父子進(jìn)程間不共享這些存儲空間,它們之間共享的存儲空間只有代碼段。
函數(shù)說明
一個現(xiàn)有進(jìn)程可以調(diào)用fork函數(shù)創(chuàng)建一個新進(jìn)程。由fork創(chuàng)建的新進(jìn)程被稱為(childprocess)子進(jìn)程。fork函數(shù)被調(diào)用一次但返回兩次。兩次返回的唯一區(qū)別是子進(jìn)程中返回0值而父進(jìn)程中返回子進(jìn)程ID。
子進(jìn)程是父進(jìn)程的副本,它將獲得父進(jìn)程數(shù)據(jù)空間、堆、棧等資源的副本。注意,子進(jìn)程持有的是上述存儲空間的“副本”,這意味著父子進(jìn)程間不共享這些存儲空間。
UNIX將復(fù)制父進(jìn)程的地址空間內(nèi)容給子進(jìn)程,因此,子進(jìn)程有了獨(dú)立的地址空間。在不同的UNIX系統(tǒng)下,我們無法確定fork之后是子進(jìn)程先運(yùn)行還是父進(jìn)程先運(yùn)行,這依賴于系統(tǒng)的實(shí)現(xiàn)。所以在移植代碼的時候我們不應(yīng)該對此作出任何的假設(shè)。
為什么fork會返回兩次?
由于在復(fù)制時復(fù)制了父進(jìn)程的堆棧段,所以兩個進(jìn)程都停留在fork函數(shù)中,等待返回。因此fork函數(shù)會返回兩次,一次是在父進(jìn)程中返回,另一次是在子進(jìn)程中返回,這兩次的返回值是不一樣的。
fork調(diào)用的一個奇妙之處就是它僅僅被調(diào)用一次,卻能夠返回兩次,它可能有三種不同的返回值:在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID;在子進(jìn)程中,fork返回0;如果出現(xiàn)錯誤,fork返回一個負(fù)值。
在fork函數(shù)執(zhí)行完畢后,如果創(chuàng)建新進(jìn)程成功,則出現(xiàn)兩個進(jìn)程,一個是子進(jìn)程,一個是父進(jìn)程。在子進(jìn)程中,fork函數(shù)返回0,在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID。我們可以通過fork返回的值來判斷當(dāng)前進(jìn)程是子進(jìn)程還是父進(jìn)程。引用一位網(wǎng)友的話來解釋fork函數(shù)返回的值為什么在父子進(jìn)程中不同?!捌鋵?shí)就相當(dāng)于鏈表,進(jìn)程形成了鏈表,父進(jìn)程的fork函數(shù)返回的值指向子進(jìn)程的進(jìn)程id,因?yàn)樽舆M(jìn)程沒有子進(jìn)程,所以其fork函數(shù)返回的值為0。
調(diào)用fork之后,數(shù)據(jù)、堆棧有兩份,代碼仍然為一份但是這個代碼段成為兩個進(jìn)程的共享代碼段都從fork函數(shù)中返回,箭頭表示各自的執(zhí)行處。當(dāng)父子進(jìn)程有一個想要修改數(shù)據(jù)或者堆棧時,兩個進(jìn)程真正分裂。fork函數(shù)的特點(diǎn)概括起來就是“調(diào)用一次,返回兩次”,在父進(jìn)程中調(diào)用一次,在父進(jìn)程和子進(jìn)程中各返回一次。fork的另一個特性是所有由父進(jìn)程打開的描述符都被復(fù)制到子進(jìn)程中。父、子進(jìn)程中相同編號的文件描述符在內(nèi)核中指向同一個file結(jié)構(gòu)體,也就是說,file結(jié)構(gòu)體的引用計數(shù)要增加。
