1. 程式人生 > >fork呼叫後,子程序與父程序是否共享變數

fork呼叫後,子程序與父程序是否共享變數

回顧fork呼叫
fork系統呼叫從已存在的程序中生成一個新的程序,這個新的程序就是子程序,我們可以通過fork系統呼叫的返回值來區分子程序還是父程序。
一個程序,包括程式碼、資料和分配給程序的資源。fork()函式通過系統呼叫建立一個與原來程序幾乎完全相同的程序。
我們的問題是,程序中的變數是否由父程序和子程序共享?
背景
最開始我簡單的認為,似乎是看視訊裡說的。對於只讀變數,父程序和子程序是共享的。對於進行寫操作的變數,父程序和子程序是獨立。後來在自己做實驗是發現這樣一個現象,於是就進行了思考。如圖所示
這是程式碼

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h> #include<unistd.h> int main(){ pid_t pid; int num=0; pid=fork(); if(pid==0){ num+=10; printf("child %d\n",num); printf("child %d\n",&num); } if(pid>0){ num+=20; printf("parent %d\n",num); printf
("parent %d\n",&num); } return 0; }

這是執行結果

parent 20
parent -948260088
child 10
child -948260088

分析
由於num在子程序中加上了10,結果為10,父程序中加上了20,結果為20.所以num這個變數對於父程序和子程序來說應該是獨立的。
但是看兩個程序中的num的地址,發現居然是一樣的,這就有點奇怪了,難道父子程序中的num變數是共享的麼。可這和之前的解釋是相互矛盾的。
仔細想一想後
一個程式中程式碼中的變數要麼是事先宣告好的,要麼是動態分配的,在這裡num顯然是事先分配好的變數,也就是說,num在宣告時其地址就已經確定就好了。我們的num變數是在fork呼叫前定義的。所以無論如何num變數的地址是不會改變的。可是想一想我們列印的num地址是不是真正的地址呢?答案是否定的,這個地址是給我們程式設計師使用的虛擬記憶體地址,最後都會通過核心對映到實際的實體記憶體中去,所以,如果要出現我們程式執行的這種情況,只有一種可能,我們列印的是num的虛擬記憶體地址,它是無論如何不會改變的,可是num變數的值是獨立的,那是因為通過num的地址對映的實體地址是不一樣的,所以在實體記憶體中num應該是由兩個的,只是他們兩都對映到一個虛擬記憶體地址。
總結


上面並沒有說的很清楚,並且帶有個人猜想的成分,這裡經過相關資料的查詢,發現差不多是這樣子的。

首先,子程序是完全複製父程序的,所以num的地址是一樣的,可是子程序複製的是虛擬地址空間,而非物理空間。如果,子程序和父程序對變數只讀,也就是說變數不會被改變,這時候,變量表現為共享的,此時物理空間只有一份。如果說父程序或者子程序需要改變變數,那麼程序將會對實體記憶體進行復制,這個時候變數是獨立的,也就是說,實體記憶體中存在兩份空間。

長沙理工大學,17級大一