fork函數(shù)的寫時(shí)拷貝
#include
#include
#include
#include
#include
#include
int main()
{
char p = g;
int number = 11;
if(fork()==0) /*子進(jìn)程*/
{
p = c; /*子進(jìn)程對數(shù)據(jù)的修改*/
printf("p = %c , number = %d ",p,number);
exit(0);
}
/*父進(jìn)程*/
number = 14; /*父進(jìn)程對數(shù)據(jù)修改*/
printf("p = %c , number = %d ",p,number);
exit(0);
}
編譯調(diào)試:
[gong@Gong-Computer cprogram]$ gcc -g TestWriteCopyTech.c -o TestWriteCopyTech
[gong@Gong-Computer cprogram]$ ./TestWriteCopyTech
p = g , number = 14 -----父進(jìn)程打印內(nèi)容
[gong@Gong-Computer cprogram]$ p = c , number = 11 -----子進(jìn)程打印內(nèi)容
原因分析:
由于存在企圖進(jìn)行寫操作的部分,因此會發(fā)生寫時(shí)拷貝過程,子進(jìn)程中對數(shù)據(jù)的修改,內(nèi)核就會創(chuàng)建一個(gè)新的物理內(nèi)存空間。然后再次將數(shù)據(jù)寫入到新的物理內(nèi)存空間中。可知,對新的區(qū)域的修改不會改變原有的區(qū)域,這樣不同的空間就區(qū)分開來。但是沒有修改的區(qū)域仍然是多個(gè)進(jìn)程之間共享。
fork函數(shù)的代碼段基本是只讀類型的,而且在運(yùn)行階段也只是復(fù)制,并不會對內(nèi)容進(jìn)行修改,因此父子進(jìn)程是共享代碼段,而數(shù)據(jù)段、Bss段、堆棧段等會在運(yùn)行的過程中發(fā)生寫過程,這樣就導(dǎo)致了不同的段發(fā)生相應(yīng)的寫時(shí)拷貝過程,實(shí)現(xiàn)了不同進(jìn)程的獨(dú)立空間。
但是需要注意的是文件操作,由于文件的操作是通過文件描述符表、文件表、v-node表三個(gè)聯(lián)系起來控制的,其中文件表、v-node表是所有的進(jìn)程共享,而每個(gè)進(jìn)程都存在一個(gè)獨(dú)立的文件描述符表。父子進(jìn)程虛擬存儲空間的內(nèi)容是大致相同的,父子進(jìn)程是通過同一個(gè)物理區(qū)域存儲文件描述符表,但如果修改文件描述符表,也會發(fā)生寫時(shí)拷貝操作,只有這樣才能保證子進(jìn)程中對文件描述符的修改,不會影響到父進(jìn)程的文件描述符表。例如close操作,因?yàn)閏lose會導(dǎo)致文件的描述符的值發(fā)生變化,相當(dāng)于發(fā)生了寫操作,這是產(chǎn)生了寫時(shí)拷貝過程,實(shí)現(xiàn)新的物理空間,然后再次發(fā)生close操作,這樣就不會產(chǎn)生子進(jìn)程中文件描述符的關(guān)閉而導(dǎo)致父進(jìn)程不能訪問文件。
測試函數(shù):
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd;
char c[3];
char *s = "TestFs";
fd = open("foobar.txt",O_RDWR,0);
if(fork()==0) //子進(jìn)程
{
fd = 1;//stdout
write(fd,s,7);
exit(0);
}
//父進(jìn)程
read(fd,c,2);
c[2]=