clone()、fork()、vfork()都是Linux的系統調用。
進程一般由代碼段、數據段和PCB進程控制塊組成。
fork 創造的子進程復制了父親進程的資源,包括內存的內容task_struct內容,新舊進程使用同一代碼段,復制數據段和堆棧段,這里的復制采用了注明的copy_on_write技術,即一旦子進程開始運行,則新舊進程的地址空間已經分開,兩者運行獨立。
優點是子進程的執行獨立於父進程,具有良好的並發性。
缺點是兩者的通信需要專門的通信機制,如pipe、fifo和system V等。
其實在復制過程中,子進程復制了父進程的task_struct,系統堆棧空間和頁面表,在子進程運行前,兩者指向同一頁面。而當子進程改變了父進程的變量時候,會通過copy_on_write的手 段為所涉及的頁面建立一個新的副本。因此fork效率並不低。
vfork函數創建的子進程完全運行在父進程的地址空間上,子進程對虛擬地址空間任何數據的修改都為父進程所見。這與fork是完全不同的,fork進程是獨立的空間。另外一點不同的是vfork創建的子進程后,父進程會被阻塞,直到子進程執行exec()和exit()。
當創建子進程的目的僅僅是為了調用exec()執行另一個程序時,子進程不會對父進程的地址空間又任何引用。因此,此時對地址空間的復制是多余的,通過vfork可以減少不必要的開銷。
系統調用fork()和vfork()是無參數的,而clone()則帶有參數。fork()是全部復制,vfork()是共享內存,而clone()是則可以將父進程資源有選擇地復制給子進程,而沒有復制的數據結構則通過指針的復制讓子進程共享,具體要復制哪些資源給子進程,由參數列表中的clone_flags來決定。另外,clone()返回的是子進程的pid。
輕量級進程由clone()函數創建。clone函數功能強大,帶了眾多參數,因此由他創建的進程要比前面2種方法要復雜。clone可以讓你有選擇性的繼承父進程的資源,你可以選擇想vfork一樣和 父進程共享一個虛存空間,從而使創造的是線程,你也可以不和父進程共享,你甚至可以選擇創造出來的進程和父進程不再是父子關系,而是兄弟關系
do_fork的參數與clone系統調用的參數類似, 不過多了一個regs(內核棧保存的用戶模式寄存器). 實際上其他的參數也都是用regs取的
- clone:
- clone的API外衣, 把fn, arg壓入用戶棧中, 然后引發系統調用. 返回用戶模式后下一條指令就是fn.
- sysclone: parent_tidptr, child_tidptr都傳到了 do_fork的參數中
- sysclone: 檢查是否有新的棧, 如果沒有就用父進程的棧 (開始地址就是regs.esp)
- fork, vfork:
- 服務例程就是直接調用do_fork, 不過參數稍加修改
- clone_flags:
- sys_fork: SIGCHLD|0;
- sys_vfork: SIGCHLD| (clone_vfork | clone_vm)
- 用戶棧: 都是父進程的棧.
- parent_tidptr, child_ctidptr都是NULL.