對fork,vfork 與exec的一些個人見解

轉載來源http://blog.chinaunix.net/uid-20528014-id-4068931.html

博客:fireaxe.blog.chinaunix.net

1) 先說說fork

fork在linux中用於進程的創建。它實際上是複製了一個與父進程(就是調用fork的進程)一模一樣的子進程。其主要複製的內容包括: 進程控制塊PCD、數據段與堆棧。代碼段是共享的。因爲代碼段是read-only的,不用擔心改寫的問題,大家共用一塊代碼也沒什麼問題。
調用完fork後,兩個進程就分道揚鑣了,各幹各的互不干擾。可問題是他們兩個什麼都是一樣的,那如何區分誰是誰呢?總不能兩個進程幹一樣的活吧。答案是用fork的返回值區分。返回值是0的子進程,非0的就是父進程。
舉個形象點的例子: 新人進公司時都會給分配一臺新電腦,一般IT部門都會給與裝上Windows操作系統和一堆軟件。一臺電腦就類似於一個進程,所有電腦最開始都是一樣的,唯一的區別是使用的人不一樣(相當於進程號)。財務科用它算賬,咱們程序猿用它coding。

2) exec的作用
exec指的是一組函數,但他們的用法差別不大,這裏就用exec代替了。
exec的目的是啓動一個新的程序,它會加載一個新的代碼段、新的數據段與堆棧。
在借用上面的例子: 研發部門分配的是預裝Windows的電腦,可是開發環境是Linux的,所以要重裝系統。這個過程就相當於exec。重裝系統第一要務是什麼呢?就是要先備份數據。exec也是一樣的,這一過程不可逆。
(注意: exec一旦調用成功,不會再返回)

3) 爲何fork與exec要配合使用
通常來講只有linux是不夠的,日常辦公還是用Windows爽,所以當開發人員需要linux環境時,通常的做法是再申請一臺電腦,然後在新電腦上安裝linux。
一個進程也一樣。父進程並不希望調用新程序後自己就消失,所以就需要fork與exec配合起來使用。先用fork啓動一個子進程,然後讓它去代替自己去死(啓動一個新進程)。
這種用法也是進程創建的標準用法,很少有兩個函數單獨使用情況。

4) 爲何需要vfork
上面提到了fork與exec配合使用的情況有一個缺點: 效率有點低。
fork會複製一份獨立的數據段與堆棧,而exec的調用會產生新的數據段與堆棧。這種情況下,前面複製數據段與代碼段的行爲就沒什麼意義了。而複製又很浪費時間與空間。爲了提高效率,產生了vfork。vfork不會複製數據段與堆棧,它產生的子進程會使用父進程的數據段與代碼段。因此用vfork代替fork,從效率上看很划算。

5) vfork的缺點
vfork帶來效率提升的同時,也引入了一些麻煩。首先是數據段與堆棧的共享。父子進程可能互相影響。爲了降低風險,vfork調用後父進程會阻塞到子進程exec被調用。這樣能夠避免父進程影響子進程。而子進程對父進程的影響則要靠程序員自己控制。
因爲共享,子進程對堆棧與數據段的任何改動都會對父進程產生同樣影響。所以調用vfork後,要儘快調用exec,以降低風險。vfork與exec之間的操作也要小心的設計。
另外,vfork結束時必須調用exit,否則會導致父進程的異常,原因似乎是堆棧被改寫了。
互相影響的風險非常之大,所以能不用vfork,儘量不要用。

6) fork真的比vfork效率低嗎
實際上,fork並不會立刻複製數據段與堆棧。而是在它們發生修改時纔會複製,而且通過MMU的使用,每次複製只會複製4K。通過寫時拷貝的方式,fork極大的提升了效率,而且安全性更高。

7) vfork難道沒用了嗎
個人覺得vfork還是有用的,但最好能對 vfork+exec 的使用加以限制。
很多操作系統提供了Spawn的操作,這個類似於vfork+exec,但通過吧兩個接口封裝成一個函數的方式,有效的避免了子進程改寫父進程的風險。所以在系統設計時,可以先考慮提供一組vfork加exec的封裝。

8) 結束語
linux的系統調用強調的是簡單,它們只提供最基本的操作,這樣做的好處是靈活。但過靈活度越高,則對程序員的要求越高。
exec系列共有六個函數,所以與fork與vfork配合後會產生12中組合。我的想法是隻提供下面三個接口,儘量限制程序員的靈活性:
fork
execlp
spawn (vfork + execlp)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章