Fork 與vfork到底什麼區別

      fork創建一個進程時,子進程只是完全複製父進程的資源,這樣得到的子進程獨立於父進程,具有良好的併發性,但是二者之間的通訊需要通過專門的通訊機制,如:PIPE 、FIFO, IPC(消息隊列、信號量和共享內存)機制等, 另外通過fork創建子進程系統開銷很大,需要將上面描述的每種資源都複製一個副本。這樣看來,fork是一個 開銷十分大的系統調用,這些開銷並不是所有的情況下都是必須的,比如某進程fork出一個子進程後,其子進程僅僅是爲了調用exec執行另一個執行文件,那麼在fork過程中對於虛存空間的複製將是一個多餘的過程(由於Linux中是採取了copy-on-write技術,所以這一步驟的所做的工作只是虛存管理部分的複製以及頁表的創建,而並沒有包括物理也面的拷貝);
 
     vfork系統調用不同於fork,用vfork創建的子進程共享地址空間,也就是說子進程完全運行在父進程的地址空間上,子進程對虛擬地址空間任何數據的修改同樣爲父進程所見。但是用 vfork創建子進程後,父進程會被阻塞直到子進程調用exec或exit。這樣的好處是在子進程被創建後僅僅是爲了調用exec執行另一個程序時,因爲它就不會對父進程的地址空間有任何引用,所以對地址空間的複製是多餘的,通過vfork可以減少不必要的開銷。
按指定條件創建子進程。Linux內核在2.0.x版本就已經實現了輕量進程,應用程序可以通過一個統一的clone()系統調用接口,用不同的參數指定創建輕量進程還是普通進程。在內核中,clone()調用經過參數傳遞和解釋後會調用do_fork(),這個核內函數同時也是fork()、vfork()系統調用的最終實現
在fork之後,子進程和父進程都會繼續執行fork調用之後的指令。子進程是父進程的副本。它將獲得父進程的數據空間,堆和棧的副本,這些都是副本,父子進程並不共享這部分的內存。也就是說,子進程對父進程中的同名變量進行修改並不會影響其在父進程中的值。但是父子進程又共享一些東西,簡單說來就是程序的正文段。正文段存放着由cpu執行的機器指令,通常是read-only的。
由於在fork之後我們常常都是跟個exec在後面,所以爲了提高效率,很多的實現並不完全複製數據段和堆、棧,而是採用寫時複製,有點類似於某些cache與內存數據的同步方法。
     另一種提高效率的方法就是使用vfork,vfork最早起源於2.9BSD,它與fork的不同就在於它並不將父進程的地址空間完全複製到子進程中,因爲子進程會立即調用exec。vfork出來的子進程是在父進程的空間中運行的,它的存在就是爲了exec調用,所以它不需要複製這些東西,因爲複製了也沒有用。如果這時子進程修改了某個變量,這將影響到父進程。
     vfork與fork的另一區別是:vfork保證子進程先運行,在它調用exec或exit後父進程纔可能調度運行。而fork的父子進程運行順序是不定的,它取決於內核的調度算法。
     所以,fork的時候,程序代碼被複用了——我指的程序代碼就是由cpu執行的機器指令部分,這與有多少個進程在運行無關,即使是頻繁執行的程序在存儲器中也只需一個副本,而且它在執行期可能是read-only的。當然,如果你exec了,那就是另一碼事了。
     另外,父進程中的數據空間和堆、棧可能會產生副本,具體情況要看你使用的是vfork還是fork。fork會產生副本,而vfork則共享這部分內存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章