日歷
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|
統(tǒng)計(jì)
- 隨筆 - 23
- 文章 - 122
- 評(píng)論 - 31
- 引用 - 0
導(dǎo)航
常用鏈接
留言簿(2)
隨筆檔案(23)
文章分類(270)
文章檔案(122)
我的豆瓣
搜索
最新評(píng)論

閱讀排行榜
評(píng)論排行榜
|
操作系統(tǒng)的作業(yè)要求編程實(shí)現(xiàn)一個(gè)命令解釋器的接口,要求用多進(jìn)程實(shí)現(xiàn),fork的方法還不會(huì),網(wǎng)上google了一下,發(fā)現(xiàn)在chinaunix論壇里面有很詳細(xì)的解釋 以下內(nèi)容轉(zhuǎn)至:http://www.chinaunix.net/jh/23/311067.html 問題如下: #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 %d\n",getpid()); else printf("i am the parent process, my process id is %d\n",getpid()); }
結(jié)果是 [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是多少,都應(yīng)該只有一行才對(duì)
網(wǎng)友解答: 要搞清楚fork的執(zhí)行過程,就必須先講清楚操作系統(tǒng)中的“進(jìn)程(process)”概念。一個(gè)進(jìn)程,主要包含三個(gè)元素:
o. 一個(gè)可以執(zhí)行的程序; o. 和該進(jìn)程相關(guān)聯(lián)的全部數(shù)據(jù)(包括變量,內(nèi)存空間,緩沖區(qū)等等); o. 程序的執(zhí)行上下文(execution context)。
不妨簡單理解為,一個(gè)進(jìn)程表示的,就是一個(gè)可執(zhí)行程序的一次執(zhí)行過程中的一個(gè)狀態(tài)。操作系統(tǒng)對(duì)進(jìn)程的管理,典型的情況,是通過進(jìn)程表完成的。進(jìn)程表中的每一個(gè)表項(xiàng),記錄的是當(dāng)前操作系統(tǒng)中一個(gè)進(jìn)程的情況。對(duì)于單 CPU的情況而言,每一特定時(shí)刻只有一個(gè)進(jìn)程占用 CPU,但是系統(tǒng)中可能同時(shí)存在多個(gè)活動(dòng)的(等待執(zhí)行或繼續(xù)執(zhí)行的)進(jìn)程。
一個(gè)稱為“程序計(jì)數(shù)器(program counter, pc)”的寄存器,指出當(dāng)前占用 CPU的進(jìn)程要執(zhí)行的下一條指令的位置。
當(dāng)分給某個(gè)進(jìn)程的 CPU時(shí)間已經(jīng)用完,操作系統(tǒng)將該進(jìn)程相關(guān)的寄存器的值,保存到該進(jìn)程在進(jìn)程表中對(duì)應(yīng)的表項(xiàng)里面;把將要接替這個(gè)進(jìn)程占用 CPU的那個(gè)進(jìn)程的上下文,從進(jìn)程表中讀出,并更新相應(yīng)的寄存器(這個(gè)過程稱為“上下文交換(process context switch)”,實(shí)際的上下文交換需要涉及到更多的數(shù)據(jù),那和fork無關(guān),不再多說,主要要記住程序寄存器pc指出程序當(dāng)前已經(jīng)執(zhí)行到哪里,是進(jìn)程上下文的重要內(nèi)容,換出 CPU的進(jìn)程要保存這個(gè)寄存器的值,換入CPU的進(jìn)程,也要根據(jù)進(jìn)程表中保存的本進(jìn)程執(zhí)行上下文信息,更新這個(gè)寄存器)。
好了,有這些概念打底,可以說fork了。當(dāng)你的程序執(zhí)行到下面的語句: pid=fork(); 操作系統(tǒng)創(chuàng)建一個(gè)新的進(jìn)程(子進(jìn)程),并且在進(jìn)程表中相應(yīng)為它建立一個(gè)新的表項(xiàng)。新進(jìn)程和原有進(jìn)程的可執(zhí)行程序是同一個(gè)程序;上下文和數(shù)據(jù),絕大部分就是原進(jìn)程(父進(jìn)程)的拷貝,但它們是兩個(gè)相互獨(dú)立的進(jìn)程!此時(shí)程序寄存器pc,在父、子進(jìn)程的上下文中都聲稱,這個(gè)進(jìn)程目前執(zhí)行到fork調(diào)用即將返回(此時(shí)子進(jìn)程不占有CPU,子進(jìn)程的pc不是真正保存在寄存器中,而是作為進(jìn)程上下文保存在進(jìn)程表中的對(duì)應(yīng)表項(xiàng)內(nèi))。問題是怎么返回,在父子進(jìn)程中就分道揚(yáng)鑣。
父進(jìn)程繼續(xù)執(zhí)行,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn),使這個(gè)調(diào)用在父進(jìn)程中返回剛剛創(chuàng)建的子進(jìn)程的pid(一個(gè)正整數(shù)),所以下面的if語句中pid<0, pid==0的兩個(gè)分支都不會(huì)執(zhí)行。所以輸出i am the parent process
子進(jìn)程在之后的某個(gè)時(shí)候得到調(diào)度,它的上下文被換入,占據(jù) CPU,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn),使得子進(jìn)程中fork調(diào)用返回0。所以在這個(gè)進(jìn)程(注意這不是父進(jìn)程了哦,雖然是同一個(gè)程序,但是這是同一個(gè)程序的另外一次執(zhí)行,在操作系統(tǒng)中這次執(zhí)行是由另外一個(gè)進(jìn)程表示的,從執(zhí)行的角度說和父進(jìn)程相互獨(dú)立)中pid=0。這個(gè)進(jìn)程繼續(xù)執(zhí)行的過程中,if語句中pid<0不滿足,但是pid==0是true。所以輸出i am the child process
我想你比較困惑的就是,為什么看上去程序中互斥的兩個(gè)分支都被執(zhí)行了。在一個(gè)程序的一次執(zhí)行中,這當(dāng)然是不可能的;但是你看到的兩行輸出是來自兩個(gè)進(jìn)程,這兩個(gè)進(jìn)程來自同一個(gè)程序的兩次執(zhí)行。
我的天,不知道說明白了沒……
問題接踵而來,又有人問: 我做如下修改
#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 %d\n",getpid()); else printf("i am the parent process, my process id is %d\n",getpid()); }
結(jié)果是 [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");后,結(jié)果是 [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
為什么只有一個(gè)fork!打印出來了?上一個(gè)為什么有2個(gè)?
又有強(qiáng)人回復(fù): 我也來一下: wujiajia 的理解有些錯(cuò)誤, printf("AAAAAAAA");//print 一次; 這里會(huì)print 2次 如果你將 printf("AAAAAA") 換成 printf("AAAAAA\n") 那么就是只打印一次了. 主要的區(qū)別是因?yàn)橛辛艘粋€(gè) \n 回車符號(hào) 這就跟Printf的緩沖機(jī)制有關(guān)了,printf某些內(nèi)容時(shí),操作系統(tǒng)僅僅是把該內(nèi)容放到了stdout的緩沖隊(duì)列里了,并沒有實(shí)際的寫到屏幕上 但是,只要看到有 \n 則會(huì)立即刷新stdout,因此就馬上能夠打印了. 運(yùn)行了printf("AAAAAA") 后, AAAAAA 僅僅被放到了緩沖里,再運(yùn)行到fork時(shí),緩沖里面的 AAAAAA 被子進(jìn)程繼承了 因此在子進(jìn)程度stdout緩沖里面就也有了 AAAAAA. 所以,你最終看到的會(huì)是 AAAAAA 被printf了2次!!!! 而運(yùn)行 printf("AAAAAA\n")后, AAAAAA 被立即打印到了屏幕上,之后fork到的子進(jìn)程里的stdout緩沖里不會(huì)有 AAAAAA 內(nèi)容 因此你看到的結(jié)果會(huì)是 AAAAAA 被printf了1次!!!!
|