Linux下C語(yǔ)言的fork()子進(jìn)程函數(shù)用法及相關(guān)問(wèn)題解析
fork
fork()函數(shù)是linux下的一個(gè)系統(tǒng)調(diào)用,它的作用是產(chǎn)生一個(gè)子進(jìn)程,子進(jìn)程是當(dāng)前進(jìn)程的一個(gè)副本,它跟父進(jìn)程有一樣的虛存內(nèi)容,但也有一些不同點(diǎn)。
但是,值得注意的是,父進(jìn)程調(diào)用fork()后,fork()返回的是生成的子進(jìn)程(如果能順利生成的話(huà))的ID。子進(jìn)程執(zhí)行的起點(diǎn)也是代碼中fork的位置,不同的是下面這段C語(yǔ)言代碼展示了fork()函數(shù)的使用方法:
// myfork.c
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
while (1) {
pid_t pid = fork();
if (pid > 0) {
// 主進(jìn)程
sleep(5);
} else if (pid == 0) {
// 子進(jìn)程
return 0;
} else {
fprintf(stderr, "fork error\n");
return 2;
}
}
}
調(diào)用fork()函數(shù)后,系統(tǒng)會(huì)將當(dāng)前進(jìn)程的絕大部分資源拷貝一份(其中的copy-on-write技術(shù)這里不詳述),該函數(shù)的返回值有三種情況,分別是:
1.大于0,表示當(dāng)前進(jìn)程為父進(jìn)程,返回值是子進(jìn)程號(hào);
2.等于0,表示當(dāng)前進(jìn)程是子進(jìn)程;
3.小于0(確切地說(shuō)是等于-1),表示fork()調(diào)用失敗。
看兩個(gè)比較有意思的C語(yǔ)言題目。
第一題:計(jì)算下面代碼理論上總共打印了多少行:(網(wǎng)易2011筆試題)
#include
#include
#include
int main(){
int i;
for(i = 0; i<5; i++){
fork();
printf("%d\n",getpid());
fflush(stdout);
}
}
問(wèn)題解答:
這道問(wèn)題并不難,最快的想法就是2+4+8+16+32,因?yàn)榈谝粚拥膒rintf會(huì)有兩個(gè)進(jìn)程打印,第二層會(huì)增加到4個(gè),以此往下,就得出62行。
但我這里打算采用另外一種方法,一種更加直觀的方法,就是直接數(shù)出來(lái),這樣會(huì)避免大腦短路,而且對(duì)下一題目有幫助。
要直接數(shù)出來(lái)也很簡(jiǎn)單,只是有些繁瑣,因?yàn)槊垦h(huán)一次,都會(huì)打印一行并且產(chǎn)生一個(gè)子進(jìn)程,子進(jìn)程又會(huì)繼續(xù)循環(huán)打印并產(chǎn)生新的進(jìn)程。我們可以在草稿紙上畫(huà)一棵樹(shù),畫(huà)出每個(gè)進(jìn)程的子進(jìn)程以及循環(huán)次數(shù),如果你眼力夠好,腦子不容易亂,這種方法很快會(huì)讓你得到正確答案。但我恰好腦子不是能夠保證清醒的人,畫(huà)了三遍樹(shù)得到的都是錯(cuò)誤答案。
隨后,我在紙上用了一種更簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)——隊(duì)列進(jìn)行計(jì)算,并且順利得出了答案。我是這樣計(jì)算的:
首先,主進(jìn)程會(huì)循環(huán)5次,則我們將5壓入到隊(duì)列中:
queue =" 5 "; sum = 0; //sum是總打印次數(shù)
主進(jìn)程會(huì)循環(huán)5次,打印5行并且產(chǎn)生5個(gè)子進(jìn)程,這5個(gè)子進(jìn)程分別會(huì)打印5,4,3,2,1行,則我們將這5個(gè)數(shù)放入隊(duì)列,并將第一個(gè)5出隊(duì)列加入到sum中:
queue = " 5 4 3 2 1 "; sum = sum + 5;
這樣,我們?cè)偃£?duì)列首元素,即5,他會(huì)打印5行,并且生成4個(gè)子進(jìn)程,子進(jìn)程的分別會(huì)打印4,3,2,1行,我們把這4個(gè)數(shù)放入到隊(duì)列中,并將第一個(gè)5出隊(duì)列加入到sum中:
queue = " 4 3 2 1 4 3 2 1"; sum = sum + 5;
我們繼續(xù)重復(fù)上面的工作,取首元素4,他會(huì)打印4行,并且會(huì)聲稱(chēng)3個(gè)子進(jìn)程,子進(jìn)程分別打印3,2,1行,重復(fù)上面的入隊(duì)列和出隊(duì)列操作:
queue = " 3 2 1 4 3 2 1 3 2 1 "; sum = sum + 4;
這樣,以此重復(fù)以上的操作,當(dāng)遇到元素1的時(shí)候,只有出隊(duì)列而沒(méi)有入隊(duì)列的操作,因?yàn)橹淮蛴?行的子進(jìn)程不會(huì)再循環(huán)產(chǎn)生新的子進(jìn)程。最后,當(dāng)隊(duì)列中不再有元素的時(shí)候,sum就是總共打印的行數(shù)。
這種方法的有點(diǎn)是你可以很輕松、很清醒的在紙上把隊(duì)列寫(xiě)出來(lái)并算出答案,缺點(diǎn)是如果你加法不好,很容易算錯(cuò)答案!
第二題:問(wèn)下面的代碼執(zhí)行后總共產(chǎn)生了多少進(jìn)程(不包括主進(jìn)程)?(2009 EMC筆試)
#include
int main(){
fork();
fork() && fork() || fork();
fork();
}
這個(gè)題目跟上一個(gè)對(duì)比起來(lái)就稍微有點(diǎn)難度了,因?yàn)槟憔退惝?huà)樹(shù)也有可能算錯(cuò)!
我個(gè)人感覺(jué)這個(gè)題目考察兩方面的知識(shí):1、開(kāi)頭所講的fork()返回值;2、&&和||的運(yùn)算。
讓我們現(xiàn)討論下&&和||的運(yùn)算再來(lái)繼續(xù)討論這個(gè)題目。&&是“邏輯與”操作,如果兩個(gè)操作數(shù)有一個(gè)為0,則整個(gè)式子為0。標(biāo)準(zhǔn)C中規(guī)定,如果&&運(yùn)算符的左操作數(shù)為0,則不計(jì)算右操作數(shù);如果左操作數(shù)為1,才計(jì)算右操作數(shù)。
與之類(lèi)似,||操作符是“邏輯或”操作,標(biāo)準(zhǔn)C規(guī)定如果||運(yùn)算符左操作數(shù)為1,則不計(jì)算右操作數(shù);如果左操作數(shù)為0,則計(jì)算右操作數(shù)。
繼續(xù)來(lái)看我們的題目,我們把題目中的5個(gè)fork()分別標(biāo)記為A,B,C,D,E。則我們可以看到,主進(jìn)程一共產(chǎn)生4個(gè)進(jìn)程,分別產(chǎn)生在A,B,C,E位置上(B,C兩個(gè)fork()返回值都不是0,因此B&&C不為0,因此不計(jì)算D)。讓我們?nèi)匀徊捎蒙项}的算法,使用一個(gè)隊(duì)列:
首先,將主進(jìn)程產(chǎn)生子進(jìn)程的位置放到隊(duì)列中:
queue = " A B C E "; sum = 0;
我們從隊(duì)列中取首元素A,我們分析A處產(chǎn)生的進(jìn)程,發(fā)現(xiàn)它會(huì)在B, C, E三處產(chǎn)生子進(jìn)程,我們把這三個(gè)元素插入到隊(duì)列中,并將sum+1。
queue = " B C E B C E "; sum ++;
然后,我們從隊(duì)列中取出首元素B,B處產(chǎn)生的子進(jìn)程稍稍不一樣,因?yàn)樽舆M(jìn)程中B所代表的fork()返回值為0,因此C得不到執(zhí)行,而D會(huì)得到執(zhí)行。因此,B處產(chǎn)生的子進(jìn)程會(huì)執(zhí)行D, E,將這兩個(gè)元素送入隊(duì)列,sum++:
queue = " C E B C E D E "; sum ++;
下面,我們?nèi)∈自谻,分析發(fā)現(xiàn),C處產(chǎn)生的進(jìn)程會(huì)執(zhí)行D, E,送入隊(duì)列并且sum++:
queue = " E B C E D E D E "; sum ++;
同上一題一樣,依次這樣執(zhí)行,遇到E則沒(méi)有元素入隊(duì)列,直到最后隊(duì)列為空,sum就是總共產(chǎn)生的進(jìn)程個(gè)數(shù)。
欄 目:C語(yǔ)言
下一篇:簡(jiǎn)單實(shí)現(xiàn)C++復(fù)數(shù)計(jì)算器
本文標(biāo)題:Linux下C語(yǔ)言的fork()子進(jìn)程函數(shù)用法及相關(guān)問(wèn)題解析
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/2230.html
您可能感興趣的文章
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用函數(shù)刪除字符
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)式函數(shù)庫(kù)
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段函數(shù)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排序法函數(shù)
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段函數(shù)
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?


