做網(wǎng)站的人屬于什么行業(yè)河北軟文搜索引擎推廣公司
文章目錄
- 前言
- fork 基本概念
- 代碼演示
- 示例1:體會 fork 函數(shù)返回值的作用
- 示例2:創(chuàng)建多進(jìn)程,加深對 fork 函數(shù)的理解
前言
本篇介紹 fork 函數(shù)。
fork 基本概念
pid_t fork(void)
fork 的英文含義是"分叉",在這里就是 創(chuàng)建子進(jìn)程。返回值:失敗:-1成功,兩個返回值:如果當(dāng)前進(jìn)程是 父進(jìn)程,則返回子進(jìn)程的 id如果當(dāng)前進(jìn)程是 子進(jìn)程,返回 0,返回 0 也表示創(chuàng)建子進(jìn)程成功可以通過 fork 的返回值判斷當(dāng)前進(jìn)程是 父進(jìn)程 還是 子進(jìn)程。
是的,你沒有看錯,fork 有兩個返回值,這屬實(shí)有點(diǎn)逆天。
那么 fork 的兩個返回值有什么用呢 ?
不著急回答,我們先圖解一下 fork:
左側(cè)是 a 文件中的代碼,在 fork 函數(shù)前有一堆代碼,在 fork 函數(shù)后有兩行。
在執(zhí)行 fork() 后,創(chuàng)建了一個子進(jìn)程(右圖),子進(jìn)程擁有和父進(jìn)程一樣的代碼?!酒鋵?shí)是不完全一樣的,本篇是"淺談",所以不搞復(fù)雜了】
重點(diǎn)來了:
- 子進(jìn)程擁有和父進(jìn)程一樣的代碼。
- 子進(jìn)程會和父進(jìn)程一起執(zhí)行后續(xù)的代碼。
如果只想讓父進(jìn)程執(zhí)行 代碼1,子進(jìn)程執(zhí)行 代碼2,該怎么做呢?
這里 fork 的返回值就派上用場了,fork 的返回值就是用來區(qū)分父、子進(jìn)程,為父、子進(jìn)程指定不同的業(yè)務(wù),具體實(shí)現(xiàn)會在"代碼演示"中介紹。
代碼演示
關(guān)于 fork 的概念沒什么可說的,直接結(jié)合代碼,更深入的理解 fork 吧。
示例1:體會 fork 函數(shù)返回值的作用
#include <stdio.h>
#include <unistd.h>int main() {int pid ;printf("AAA\n\n");pid = fork();if(pid > 0) {printf("開始執(zhí)行父進(jìn)程的代碼\n");printf("I'm parent, my id %d .\n", getpid());printf("父進(jìn)程的代碼執(zhí)行完畢.\n\n");} else if(pid == 0) {printf("開始執(zhí)行子進(jìn)程的代碼\n");printf("I'm child. my id: %d\n", getpid());printf("子進(jìn)程的代碼執(zhí)行完畢.\n\n");}printf("BBB.\n");
}
【非常重要】我們分析以上的輸出結(jié)果:
① 兩個分支都執(zhí)行了,這證明 fork 返回了兩個值,父、子進(jìn)程會各自進(jìn)入條件邏輯中執(zhí)行自己的代碼。
② “BBB” 被輸出了兩次,這說明 父、子進(jìn)程都會執(zhí)行 fork 函數(shù)后面的代碼,只有在遇到條件邏輯時,父子進(jìn)程 才會執(zhí)行各自的代碼。
③ 通過 fork 的返回值,可以區(qū)分 父、子進(jìn)程,從而為 父、子進(jìn)程 分配不同的業(yè)務(wù)邏輯。
④ fork 之后 父進(jìn)程 和 子進(jìn)程 的執(zhí)行順序不確定,這取決于內(nèi)核所使用的調(diào)度算法?!具@點(diǎn)沒體現(xiàn)出來,但是得知道】
到此,fork 的返回值就解釋完了。
我們最后再通過創(chuàng)建多進(jìn)程來加深對 fork 函數(shù)的理解。
示例2:創(chuàng)建多進(jìn)程,加深對 fork 函數(shù)的理解
我們知道,創(chuàng)建進(jìn)程使用的是 fork 函數(shù),那么創(chuàng)建多進(jìn)程自然就是循環(huán)調(diào)用 fork 函數(shù)了。
最容易想到的是下面這樣:
for(i=0; i<5; i++) {// 創(chuàng)建 5 個進(jìn)程pid = fork();if(pid > 0){printf("我是第 %d 個 子進(jìn)程.\n", i);}}
你仔細(xì)想想,這對嗎?
我們運(yùn)行一下:
原因就是上面提到過的第 ② 句: " 父、子進(jìn)程都會執(zhí)行 fork 函數(shù)后面的代碼,只有在遇到條件邏輯時,父子進(jìn)程 才會執(zhí)行各自的代碼 "。
也就是說父進(jìn)程在創(chuàng)建出子進(jìn)程后,子進(jìn)程也會繼續(xù)執(zhí)行 for 里面的語句,這就會導(dǎo)致子進(jìn)程繼續(xù)創(chuàng)建 子子進(jìn)程,子子進(jìn)程 也會繼續(xù)執(zhí)行 for 里面的語句,然后以此類推,子子進(jìn)程,再創(chuàng)建 子子子進(jìn)程 …
要解決這個問題,就是創(chuàng)建出子進(jìn)程后,讓子進(jìn)程執(zhí)行完邏輯后就馬上退出 for 循環(huán),不要繼續(xù)創(chuàng)建 子子進(jìn)程。
正確邏輯如下:
#include <stdio.h>
#include <unistd.h>int main() {int pid, i;for(i=0; i<5; i++) {// 創(chuàng)建 5 個進(jìn)程pid = fork();if(pid == 0){printf("我是第 %d 個 子進(jìn)程, pid: %d\n", i, getpid());break; // 直接讓子進(jìn)程跳出循環(huán)}sleep(1); // 讓進(jìn)程的輸出變得有序}return 0;
}
題外話:
因?yàn)楫?dāng)前示例只是為了演示多進(jìn)程的創(chuàng)建,加深對 fork 函數(shù)的理解,所以采用了 break 的方式假裝結(jié)束子進(jìn)程的運(yùn)行,實(shí)際上子進(jìn)程只是跳出 for 循環(huán),子進(jìn)程還是會繼續(xù)運(yùn)行 for 之外后續(xù)的語句,但是 for 之外沒有后續(xù)語句了,子進(jìn)程就執(zhí)行完畢,所以這看起來是 break 后子進(jìn)程就結(jié)束了。
實(shí)際上結(jié)束進(jìn)程應(yīng)采用特定的函數(shù),由于本篇只是 “淺談”,讓讀者專注于最核心的部分,所以就不扯多了。