小結

1.fork()爲什麼會返回2次

 

#include <unistd.h>;

#include <sys/types.h>;

main ()

{

    pid_t pid;

         pid=fork();

         if (pid < 0)

                 printf("error in fork!");

         else if (pid == 0)

                 printf("i am the child process, my process id is %dn",getpid());

         else

                 printf("i am the parent process, my process id is %dn",getpid());


}

結果是
[root@localhost c]# ./a.out
i am the child process, my process id is 4286
i am the parent process, my process id is 4285

我就想不到爲什麼兩行都打印出來了,在我想來,不管pid是多少,都應該只有一行纔對

 

chg.s 回覆於:2004-04-27 21:09:30


要搞清楚fork的執行過程,就必須先講清楚操作系統中的“進程(process)”概念。一個進程,主要包含三個元素:

o. 一個可以執行的程序;
o. 和該進程相關聯的全部數據(包括變量,內存空間,緩衝區等等);
o. 程序的執行上下文(execution context)。

不妨簡單理解爲,一個進程表示的,就是一個可執行程序的一次執行過程中的一個狀態。操作系統對進程的管理,典型的情況,是通過進程表完成的。進程表中的每一個表項,記錄的是當前操作系統中一個進程的情況。對於單 CPU的情況而言,每一特定時刻只有一個進程佔用 CPU,但是系統中可能同時存在多個活動的(等待執行或繼續執行的)進程。

一個稱爲“程序計數器(program counter, pc)”的寄存器,指出當前佔用 CPU的進程要執行的下一條指令的位置。

當分給某個進程的 CPU時間已經用完,操作系統將該進程相關的寄存器的值,保存到該進程在進程表中對應的表項裏面;把將要接替這個進程佔用 CPU的那個進程的上下文,從進程表中讀出,並更新相應的寄存器(這個過程稱爲“上下文交換(process context switch)”,實際的上下文交換需要涉及到更多的數據,那和fork無關,不再多說,主要要記住程序寄存器pc指出程序當前已經執行到哪裏,是進程上下文的重要內容,換出 CPU的進程要保存這個寄存器的值,換入CPU的進程,也要根據進程表中保存的本進程執行上下文信息,更新這個寄存器)。

好了,有這些概念打底,可以說fork了。當你的程序執行到下面的語句:
pid=fork();
操作系統創建一個新的進程(子進程),並且在進程表中相應爲它建立一個新的表項。新進程和原有進程的可執行程序是同一個程序;上下文和數據,絕大部分就是原進程(父進程)的拷貝,但它們是兩個相互獨立的進程!此時程序寄存器pc,在父、子進程的上下文中都聲稱,這個進程目前執行到fork調用即將返回(此時子進程不佔有CPU,子進程的pc不是真正保存在寄存器中,而是作爲進程上下文保存在進程表中的對應表項內)。問題是怎麼返回,在父子進程中就分道揚鑣。

父進程繼續執行,操作系統對fork的實現,使這個調用在父進程中返回剛剛創建的子進程的pid(一個正整數),所以下面的if語句中pid<0, pid==0的兩個分支都不會執行。所以輸出i am the parent process...

子進程在之後的某個時候得到調度,它的上下文被換入,佔據 CPU,操作系統對fork的實現,使得子進程中fork調用返回0。所以在這個進程(注意這不是父進程了哦,雖然是同一個程序,但是這是同一個程序的另外一次執行,在操作系統中這次執行是由另外一個進程表示的,從執行的角度說和父進程相互獨立)中pid=0。這個進程繼續執行的過程中,if語句中 pid<0不滿足,但是pid==0是true。所以輸出i am the child process...

我想你比較困惑的就是,爲什麼看上去程序中互斥的兩個分支都被執行了。在一個程序的一次執行中,這當然是不可能的;但是你看到的兩行輸出是來自兩個進程,這兩個進程來自同一個程序的兩次執行。

我的天,不知道說明白了沒……

zhaojinbo 回覆於:2004-04-28 12:35:50

fork之後,操作系統會複製一個與父進程完全相同的子進程,雖說是父子關係,但是在操作系統看來,他們更像兄弟關係,這2個進程共享代碼空間,但是數據空間是互相獨立的,子進程數據空間中的內容是父進程的完整拷貝,指令指針也完全相同,但只有一點不同,如果fork成功,子進程中 fork的返回值是0,父進程中fork的返回值是子進程的進程號,如果fork不成功,父進程會返回錯誤。
可以這樣想象,2個進程一直同時運行,而且步調一致,在fork之後,他們分別作不同的工作,也就是分岔了。這也是fork爲什麼叫fork的原因。
至於那一個最先運行,可能與操作系統有關,而且這個問題在實際應用中並不重要,如果需要父子進程協同,可以通過原語的辦法解決。

 

sniper 回覆於:2004-04-28 22:11:15

哦,偶明白了,在程序段裏用了fork();之後程序出了分岔,派生出了兩個進程。具體哪個先運行就看該系統的調度算法了。
在這裏,我們可以這麼認爲,在運行到"pid=fork();"時系統派生出一個跟主程序一模一樣的子進程。該進程的"pid=fork();"一句中pid得到的就是子進程本身的 pid;子進程結束後,父進程的"pid=fork();"中pid得到的就是父進程本身的pid。因此改程序有兩行輸出。

注:此處不準確,在子進程中pid的值爲0,通過getpid可以獲取子進程的進程id;在父進程中pid爲父進程編號。

勘誤:父進程中的pid值爲子進程進程號,只有父進程執行的getpid()纔是他自己的進程號。寒,徹底的in

 

jjl3 回覆於:2004-07-14 11:43:20

我做如下修改

#include <unistd.h>;
#include <sys/types.h>;

main ()
{
         pid_t pid;
         printf("fork!");     // printf("fork!n");
         pid=fork();

         if (pid < 0)
                 printf("error in fork!");
         else if (pid == 0)
                 printf("i am the child process, my process id is %dn",getpid());
         else
                 printf("i am the parent process, my process id is %dn",getpid());
}



結果是
[root@localhost c]# ./a.out
fork!i am the child process, my process id is 4286
fork!i am the parent process, my process id is 4285

但我改成printf("fork!n");後,結果是
[root@localhost c]# ./a.out
fork!
i am the child process, my process id is 4286
i am the parent process, my process id is 4285

爲什麼只有一個fork!打印出來了?上一個爲什麼有2個?

 

bashfulboy 回覆於:2004-07-14 22:10:52

我也來一下:
wujiajia 的理解有些錯誤,
printf("AAAAAAAA");//print 一次;    這裏會print 2次
如果你將 printf("AAAAAA") 換成 printf("AAAAAAn")    那麼就是隻打印一次了.
主要的區別是因爲有了一個 n   回車符號
這就跟Printf的緩衝機制有關了,printf某些內容時,操作系統僅僅是把該內容放到了stdout的緩衝隊列裏了,並沒有實際的寫到屏幕上
但是,只要看到有 n 則會立即刷新stdout,因此就馬上能夠打印了.
運行了printf("AAAAAA") 後, AAAAAA 僅僅被放到了緩衝裏,再運行到fork時,緩衝裏面的 AAAAAA 被子進程繼承了
因此在子進程度stdout緩衝裏面就也有了 AAAAAA.
所以,你最終看到的會是 AAAAAA 被printf了2次!!!!
而運行 printf("AAAAAAn")後, AAAAAA 被立即打印到了屏幕上,之後fork到的子進程裏的stdout緩衝裏不會有 AAAAAA 內容
因此你看到的結果會是 AAAAAA 被printf了1次!!!!

(精要)

 

albcamus 回覆於:2005-03-08 15:56:11

>;>;派生子進程的pid變量並沒有被改變是什麼意思 對於子進程來講pid不就是0嗎

1,派生子進程的進程,即父進程,其pid不變;
2,對子進程來說,fork返回給它0,但它的pid絕對不會是0;之所以fork返回0給它,是因爲它隨時可以調用getpid()來獲取自己的pid;
3,樓上的樓上的你的觀點是對的,fork之後夫子進程除非採用了同步手段,否則不能確定誰先運行,也不能確定誰先結束。認爲子進程結束後父進程才從fork返回的,這是不對的,fork不是這樣的,vfork才這樣。

 

 

2.volatile作用

3.文件描述符和文件指針區別。

4.進程間通信

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章