?相信大家在初學(xué)進(jìn)程時(shí),對(duì)fork函數(shù)創(chuàng)建進(jìn)程一定會(huì)有很多的困惑,比如:
- 1.fork做了什么事情???
- 2.為什么fork函數(shù)會(huì)有兩個(gè)返回值?
- 3.為什么fork的兩個(gè)返回值,會(huì)給父進(jìn)程諒回子進(jìn)程pid,給子進(jìn)程返回0?
- 4.fork之后:父子進(jìn)程誰(shuí)先運(yùn)行??
- 5.如何理解同一個(gè)變量,會(huì)有不同的值??
本篇文章將來(lái)仔細(xì)回答一下這些問(wèn)題。
目錄
1.如何查看進(jìn)程
2. 通過(guò)系統(tǒng)調(diào)用創(chuàng)建進(jìn)程-fork
2.1 初識(shí)fork
2.2 fork原理
1.如何查看進(jìn)程
1.1 進(jìn)程的信息可以通過(guò) /proc 系統(tǒng)文件夾查看
通過(guò)ls指令來(lái)查看所有的進(jìn)程,proc是動(dòng)態(tài)目錄結(jié)構(gòu),用來(lái)存放所有的進(jìn)程,目錄的名稱就是用進(jìn)程的id命名的。
1.2 進(jìn)程信息同樣可以使用ps(process status)工具來(lái)獲取
- 進(jìn)程id(PID)通過(guò)getpid 系統(tǒng)調(diào)用獲得
- 父進(jìn)程id(PPID)通過(guò)getppid 系統(tǒng)調(diào)用獲得
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("I am a process! myid:%d parentid:%d\n",getpid(),getppid()) ;
sleep(1);
}
return 0;
}
?我們可以使用shell再開一個(gè)窗口登錄一次進(jìn)行查看。
"aux" 是 "ps" 命令的選項(xiàng)之一,表示顯示所有用戶的所有進(jìn)程,通過(guò)查詢,可以看到你自己 ./ 啟動(dòng)的進(jìn)程,最后一個(gè)進(jìn)程是當(dāng)前的grep的查找進(jìn)程。
關(guān)于當(dāng)前工作目錄
我們?cè)贑語(yǔ)言學(xué)習(xí)文件操作是會(huì)提到當(dāng)前目錄,我們以 "w" 方式讀取文件時(shí),如果文件不存在,那么文件會(huì)在當(dāng)前工作目錄cwd下創(chuàng)建。那么一個(gè)進(jìn)程是如何找到當(dāng)前目錄的呢?
我們讓下面代碼運(yùn)行起來(lái)
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4 int main()
5 {
6 //更改當(dāng)前工作目錄
7 chdir("./wdz");//沒有這個(gè)目錄不會(huì)更改,我這里是創(chuàng)建好了這個(gè)目錄
8
9 // cwd/hello.txt
10 FILE* file = fopen("hello.txt","w");//文件不存在會(huì)在當(dāng)前工作目錄下創(chuàng)建
11 if(file==NULL)
12 {
13 return 1;
14 }
15 fclose(file);
16
17
18 while(1)
19 {
20 printf("I am a process! myid:%d parentid:%d\n",getpid(),getppid());
21 sleep(1);
22 }
23 return 0;
24 }
??這里通過(guò)修改當(dāng)前目錄已經(jīng)對(duì)將文件創(chuàng)建在更改的目錄下:
??可以發(fā)現(xiàn):
- 默認(rèn)情況下,進(jìn)程所處的目錄就是當(dāng)前工作目錄?
- 一個(gè)進(jìn)程可以找到自己的可執(zhí)行程序
- 每一個(gè)進(jìn)程都有自己的工作目錄
2. 通過(guò)系統(tǒng)調(diào)用創(chuàng)建進(jìn)程-fork
2.1 初識(shí)fork
首先使用fork創(chuàng)建一個(gè)進(jìn)程?
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
printf("我是一個(gè)父進(jìn)程我的pid:%d\n",getpid());
//創(chuàng)建一個(gè)子進(jìn)程!
pid_t id = fork();
//fork之前只有父進(jìn)程會(huì)執(zhí)行fork之前的代碼,fork之后父子進(jìn)程都要執(zhí)行后面的代碼
while(1)
{
printf("我是一個(gè)進(jìn)程,pid:%d,ppid%d,fork return:%d\n",getpid(),getppid(),id);
//這個(gè)printf函數(shù)在代碼這里只調(diào)用一次,但在運(yùn)行時(shí)調(diào)用了兩次
sleep(1);//for test
}
return 0;
}
?運(yùn)行結(jié)果:
看到這里大家的疑惑就出來(lái)了
目前可以發(fā)現(xiàn):只有父進(jìn)程執(zhí)行fork之前的代碼,fork之后,父子進(jìn)程都要執(zhí)行后續(xù)的代碼!
一個(gè)函數(shù)竟然會(huì)有兩個(gè)返回值???fork成功的時(shí)候,會(huì)有兩個(gè)不同的返回值,給子進(jìn)程返回0;
給父進(jìn)程返回子進(jìn)程的pid
fork代碼的一般寫法:
1.我們?yōu)槭裁匆獎(jiǎng)?chuàng)建子進(jìn)程?
????????我們想讓子進(jìn)程協(xié)作父進(jìn)程完成一些工作,這些工作是單進(jìn)程解決不了的
2.我們創(chuàng)建子進(jìn)程是為了讓子進(jìn)程和父進(jìn)程做一樣的事情嗎??
????????我們創(chuàng)建子進(jìn)程,就是為了讓子進(jìn)程和父進(jìn)程做不一樣的事情,執(zhí)行不一樣的代碼
3. 應(yīng)該如何保證父子進(jìn)程做不一樣的事情呢?
????????可以通過(guò)判斷fork的返回值,判斷誰(shuí)是父,誰(shuí)是子,然后讓他們執(zhí)行不同的代碼片段!!
使用 if 對(duì)父子進(jìn)程分流:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
printf("我是一個(gè)父進(jìn)程我的pid:%d\n",getpid());
//創(chuàng)建一個(gè)子進(jìn)程!
//bash也是用C語(yǔ)言寫的,命令行啟動(dòng)的進(jìn)程,都是bash的子進(jìn)程,所以bash源代碼中創(chuàng)建子進(jìn)程也是用的fork
pid_t id = fork();
//fork()之后,用if進(jìn)行分流
if(id<0) return 1; //進(jìn)程創(chuàng)建失敗
else if(id == 0)
{
//子進(jìn)程
while(1)
{
printf("我是子進(jìn)程,pid:%d,ppid%d,ret:%d,正在執(zhí)行下載\n",getpid(),getppid(),id);
sleep(1);//for test
}
}
else
{
//父進(jìn)程
while(1)
{
printf("我是父進(jìn)程,pid:%d,ppid%d,ret:%d,正在執(zhí)行播放任務(wù)\n",getpid(),getppid(),id);
sleep(1);//for test
}
}
return 0;
}
執(zhí)行結(jié)果
可以發(fā)現(xiàn)通過(guò) if 對(duì)fork函數(shù)返回值進(jìn)行判斷,實(shí)現(xiàn)了父子進(jìn)程可以執(zhí)行不同的任務(wù)。
2.2 fork原理
對(duì)于上面的現(xiàn)象,我們來(lái)解答一下疑惑
- 1.fork做了什么事情???
- 2.為什么fork函數(shù)會(huì)有兩個(gè)返回值?
- 3.為什么fork的兩個(gè)返回值,會(huì)給父進(jìn)程諒回子進(jìn)程pid,給子進(jìn)程返回0?
- 4.fork之后:父子進(jìn)程誰(shuí)先運(yùn)行??
- 5.如何理解同一個(gè)變量,會(huì)有不同的值??
1. fork做了什么事情???
? ? ? ?用于創(chuàng)建一個(gè)進(jìn)程,在內(nèi)核中操作系統(tǒng)重新為其申請(qǐng)了一個(gè)PCB,并使用父進(jìn)程的PCB進(jìn)行初始化,且子進(jìn)程與父進(jìn)程同時(shí)指向相同的代碼。所以fork之前的代碼子進(jìn)程也是可以看到的。
那為什么子進(jìn)程不從頭開始執(zhí)行呢?
????????因?yàn)橛谐绦蛴?jì)數(shù)器pc,會(huì)使代碼一句一句執(zhí)行,子進(jìn)程在創(chuàng)建時(shí)和繼承父進(jìn)程的pc。所以說(shuō)也會(huì)繼續(xù)向下執(zhí)行。
2.為什么fork函數(shù)會(huì)有兩個(gè)返回值??
????????首先f(wàn)ork是一個(gè)函數(shù),如果一個(gè)函數(shù)return時(shí),說(shuō)明一個(gè)函數(shù)的核心工作已經(jīng)做完。我們知道fork之后代碼會(huì)共享,所以是fork函數(shù)做完核心工作后就會(huì)共享,return也會(huì)父子進(jìn)程共享,所以會(huì)有兩個(gè)返回值。
3.為什么fork的兩個(gè)返回值,會(huì)給父進(jìn)程諒回子進(jìn)程pid,給子進(jìn)程返回0?
????????因?yàn)橐粋€(gè)父進(jìn)程可以有多個(gè)子進(jìn)程,父進(jìn)程信息中只有pid 和 ppid,為了唯一確定子進(jìn)程,以后管理和控制子進(jìn)程,所以返回子進(jìn)程的pid,而子進(jìn)程中由于有父進(jìn)程ppid,所以返回0用來(lái)判斷進(jìn)程創(chuàng)建成功沒有即可。
4.fork之后:父子進(jìn)程誰(shuí)先運(yùn)行??
????????不確定。創(chuàng)建完成子進(jìn)程,只是一個(gè)開始。創(chuàng)建完成子進(jìn)程之后,系統(tǒng)的其他進(jìn)程,父進(jìn)程,和子進(jìn)程,接下來(lái)要被調(diào)度執(zhí)行的,當(dāng)父子進(jìn)程的PCB都被創(chuàng)建并在運(yùn)行隊(duì)列中排隊(duì)的時(shí)候,哪一個(gè)進(jìn)程的PCB先被選擇調(diào)度,那個(gè)進(jìn)程就先運(yùn)行,由操作系統(tǒng)自主決定??!由各自PCB中的調(diào)度信息(時(shí)間片,優(yōu)先級(jí)等)+調(diào)度器算法共同決定。
?5.如何理解同一個(gè)變量,會(huì)有不同的值??
????????進(jìn)程的獨(dú)立性,首先是表現(xiàn)在有各自的PCB,進(jìn)行之間不會(huì)互相影響!代碼本身是只讀的,不會(huì)影響!但是數(shù)據(jù)父子是會(huì)修改的,所以代碼共享,但是數(shù)據(jù)各個(gè)進(jìn)程必須想辦法各自私有一份??!
這個(gè)怎么做到的?通過(guò)寫時(shí)拷貝。這樣做的好處就是不用將所有的數(shù)據(jù)都進(jìn)行拷貝,當(dāng)數(shù)據(jù)需要修改時(shí)才做拷貝,可以提高效率。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-753382.html
本篇結(jié)束!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-753382.html
到了這里,關(guān)于Linux:創(chuàng)建進(jìn)程 -- fork,到底是什么?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!