vfork創建的子進程與父進程地址空間關係

在《UNIX環境高級編程》一書的第八章中,有一道課後習題如下:

回憶圖7-3典型的存儲空間佈局。由於對應於每個函數調用的棧幀通常存儲在棧中,並在調用 vfork後,子進程運行在父進程的地址空間中,如果不是在main函數中而是在另一個函數中調用vfork,以後子進程從該函數返回時,將會發生什麼情況?

作者Rich Stevens是一位大師,留下這麼一題必有其深意,於是結合《深入理解計算機系統》中的知識,寫了個程序驗證了下,受益良多。

         首先回憶下程序運行的棧幀結構(見下圖):

 

 

         從圖中可知,如果一個函數調用用了另外一個函數,那麼被調用者的棧幀則會被壓入棧頂被設置爲“當前幀”,首先執行被調用者,執行完成後,調用者的棧幀被彈出程序棧,然後從“返回地址”返回到調用者的地址空間中。

於是猜想,如果在main函數中,調用了一個函數foo,則“當前幀”爲foo的棧幀,這時,若調用vfork創建一個子進程,那麼根據vfork的語義,子進程不會完全複製父進程的地址空間,它會在父進程的地址空間中運行(這也是爲什麼vfork能保證子進程先運行,而fork不能保證。因爲vfork創建的子進程是與父進程共享地址空間,爲了避免競爭,所以就讓子進程先運行,而父進程後運行;而fork創建的子進程是父進程的副本,所以不會帶來競爭問題,誰先誰後也就無所謂了),所以它共享的是“當前幀”的地址空間,因此當子進程返回時,只會改變foo的數據,而不會改變main棧幀中的數據。

下面就來寫個程序驗證一下:

運行此程序,得到結果爲(見下圖):

 

 

果然,可以看到在foomain中,進程號都是一樣的,也就說明foomain在同一進程中。但是各個變量的值卻有差異:在foo返回後mian函數中的局部變量var依然是初始值,並沒有增加,推其原因,就是因爲子進程共享的是foo的棧幀數據,而非main函數的棧幀,所以自然也就不會改變main棧幀中的數據。

書中正文中說:子進程不會完全複製父進程的地址空間,它會在父進程的地址空間中運行。因此可以進一步得出一個結論:vfork創建的子進程,共享的是父進程當前棧幀的地址空間。

發佈了22 篇原創文章 · 獲贊 24 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章