FORK()函數(shù)的理解
子進(jìn)程和父進(jìn)程都執(zhí)行在fork函數(shù)調(diào)用之后的代碼,子進(jìn)程是父進(jìn)程的一個(gè)拷貝。例如,父進(jìn)程的數(shù)據(jù)空間、堆??臻g都會(huì)給子進(jìn)程一個(gè)拷貝,而不是共享這些內(nèi)存。
Current implementations don't perform. a complete copy of the parent's data, stack, and heap, since a fork is often followed by an exec. Instead, a technique called copy-on-write (COW) is used. These regions are shared by the parent and the child and have their protection changed by the kernel to read-only. If either process tries to modify these regions, the kernel then makes a copy of that piece of memory only, typically a page in a virtual memory system. Section 9.2 of Bach [1986] and Sections 5.6 and 5.7 of McKusick et al. [1996] provide more detail on this feature.
我們來給出詳細(xì)的注釋
#include
#include
int main(void)
{
pid_t pid;
int count=0;
/*此處,執(zhí)行fork調(diào)用,創(chuàng)建了一個(gè)新的進(jìn)程, 這個(gè)進(jìn)程共享父進(jìn)程的數(shù)據(jù)和堆棧空間等,這之后的代碼指令為子進(jìn)程創(chuàng)建了一個(gè)拷貝。 fock 調(diào)用是一個(gè)復(fù)制進(jìn)程,fock 不象線程需提供一個(gè)函數(shù)做為入口, fock調(diào)用后,新進(jìn)程的入口就在 fock的下一條語句。*/
pid = fork();
/*此處的pid的值,可以說明fork調(diào)用后,目前執(zhí)行的是父進(jìn)程還是子進(jìn)程*/
printf( Now, the pid returned by calling fork() is %dn, pid );
if ( pid>0 )
{
/*當(dāng)fork在子進(jìn)程中返回后,fork調(diào)用又向父進(jìn)程中返回子進(jìn)程的pid, 如是該段代碼被執(zhí)行,但是注意的事,count仍然為0, 因?yàn)楦高M(jìn)程中的count始終沒有被重新賦值, 這里就可以看出子進(jìn)程的數(shù)據(jù)和堆棧空間和父進(jìn)程是獨(dú)立的,而不是共享數(shù)據(jù)*/
printf( This is the parent process,the child has the pid:%dn, pid );
printf( In the parent process,count = %dn, count );
}
else if ( !pid )
{ /*在子進(jìn)程中對(duì)count進(jìn)行自加1的操作,但是并沒有影響到父進(jìn)程中的count值,父進(jìn)程中的count值仍然為0*/
printf( This is the child process.n);
printf( Do your own things here.n );
count++;
printf( In the child process, count = %dn, count );
}
else
{
printf( fork failed.n );
}
return 0;
}
也就是說,在Linux下一個(gè)進(jìn)程在內(nèi)存里有三部分的數(shù)據(jù),就是代碼段、堆棧段和數(shù)據(jù)段。代碼段,顧名思義,就是存放了程序代碼的數(shù)據(jù),假如機(jī)器中有數(shù)個(gè)進(jìn)程運(yùn)行相同的一個(gè)程序,那么它們就可以使用相同的代碼段。堆棧段存放的就是子程序的返回地址、子程序的參數(shù)以及程序的局部變量。而數(shù)據(jù)段則存放程序的全局變量,常數(shù)以及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間(比如用malloc之類的函數(shù)取得的空間)。系統(tǒng)如果同時(shí)運(yùn)行數(shù)個(gè)相同的程序,它們之間就不能使用同一個(gè)堆棧段和數(shù)據(jù)段。
仔細(xì)分析后,我們就可以知道:
一個(gè)程序一旦調(diào)用fork函數(shù),系統(tǒng)就為一個(gè)新的進(jìn)程準(zhǔn)備了前述三個(gè)段,首先,系統(tǒng)讓新的進(jìn)程與舊的進(jìn)程使用同一個(gè)代碼段,因?yàn)樗鼈兊某绦蜻€是相同的,對(duì)于數(shù)據(jù)段和堆棧段,系統(tǒng)則復(fù)制一份給新的進(jìn)程,這樣,父進(jìn)程的所有數(shù)據(jù)都可以留給子進(jìn)程,但是,子進(jìn)程一旦開始運(yùn)行,雖然它繼承了父進(jìn)程的一切數(shù)據(jù),但實(shí)際上數(shù)據(jù)卻已經(jīng)分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數(shù)據(jù)了。
fork()不僅創(chuàng)建出與父進(jìn)程代碼相同的子進(jìn)程,而且父進(jìn)程在fork執(zhí)行點(diǎn)的所有上下文場景也被自動(dòng)復(fù)制到子進(jìn)程中,包括:
——全局和局部變量
——打開的文件句柄
——共享內(nèi)存、消息等同步對(duì)象
而如果兩個(gè)進(jìn)程要共享什么數(shù)據(jù)的話,就要使用另一套函數(shù)(shmget,shmat,shmdt等)來操作?,F(xiàn)在,已經(jīng)是兩個(gè)進(jìn)程了,對(duì)于父進(jìn)程,fork函數(shù)返回了子程序的進(jìn)程號(hào),而對(duì)于子程序,fork函數(shù)則返回零,這樣,對(duì)于程序,只要判斷fork函數(shù)的返回值,就知道自己是處于父進(jìn)程還是子進(jìn)程中。
pid控制相關(guān)文章:pid控制原理
評(píng)論