1、fork函數(shù)簡(jiǎn)介
參考:http://www.itdecent.cn/p/484af1700176
一個(gè)進(jìn)程,包括代碼、數(shù)據(jù)和分配給進(jìn)程的資源。fork()函數(shù)通過(guò)系統(tǒng)調(diào)用創(chuàng)建一個(gè)與原來(lái)進(jìn)程幾乎完全相同的進(jìn)程,也就是兩個(gè)進(jìn)程可以做完全相同的事,但如果初始參數(shù)或者傳入的變量不同,兩個(gè)進(jìn)程也可以做不同的事。
一個(gè)進(jìn)程調(diào)用fork()函數(shù)后,系統(tǒng)先給新的進(jìn)程分配資源,例如存儲(chǔ)數(shù)據(jù)和代碼的空間。然后把原來(lái)的進(jìn)程的所有值都復(fù)制到新的新進(jìn)程中,只有少數(shù)值與原來(lái)的進(jìn)程的值不同。相當(dāng)于克隆了一個(gè)自己。
#include <stdio.h>
#include <unistd.h> // (windows沒(méi)有unistd.h)
int main()
{
pid_t fpid;
int count = 0;
fpid = fork();
if(fpid < 0) {
printf("error in fork\n");
} else if(fpid == 0) {
// 表示子進(jìn)程
printf("son process\n");
++count;
} else {
// > 0表示父進(jìn)程
printf("father process\n");
++count;
}
printf("fpid = %d , count = %d\n", fpid, count);
return 0;
}
(macos + xcode)運(yùn)行結(jié)果是:
father process
fpid = 13915 , count = 1
son process
fpid = 0 , count = 1
其實(shí)就相當(dāng)于鏈表,進(jìn)程形成了鏈表,父進(jìn)程的fpid(p 意味point)指向子進(jìn)程的進(jìn)程id, 因?yàn)樽舆M(jìn)程沒(méi)有子進(jìn)程,所以其fpid為0.
fork出錯(cuò)可能有兩種原因:
當(dāng)前的進(jìn)程數(shù)已經(jīng)達(dá)到了系統(tǒng)規(guī)定的上限,這時(shí)errno的值被設(shè)置為EAGAIN。
系統(tǒng)內(nèi)存不足,這時(shí)errno的值被設(shè)置為ENOMEM。
fork()產(chǎn)生的子進(jìn)程不是從#include處開(kāi)始復(fù)制代碼的,這是因?yàn)閒ork是把進(jìn)程當(dāng)前的情況拷貝一份,執(zhí)行fork時(shí),進(jìn)程已經(jīng)執(zhí)行完了int count=0;fork只拷貝下一個(gè)要執(zhí)行的代碼到新的進(jìn)程。
2、fork進(jìn)階知識(shí)
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid/n");
//ppid指當(dāng)前進(jìn)程的父進(jìn)程pid
//pid指當(dāng)前進(jìn)程的pid,
//fpid指fork返回給當(dāng)前進(jìn)程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d/n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid);
}
return 0;
}
運(yùn)行結(jié)果:
i son/pa ppid pid fpid
0 parent 2043 3224 3225
0 child 3224 3225 0
1 parent 2043 3224 3226
1 parent 3224 3225 3227
1 child 1 3227 0
1 child 1 3226 0
這份代碼比較有意思,我們來(lái)認(rèn)真分析一下:
由于第二行的輸出可以看出來(lái),當(dāng)前進(jìn)程的pid是3224,其父進(jìn)程的pid是2043,在i=0的時(shí)候執(zhí)行fork產(chǎn)生子進(jìn)程pid=3225,2043-->3224-->3225;
第三行的輸出是由pid=3224通過(guò)fork產(chǎn)生的子進(jìn)程pid=3225,每一個(gè)子進(jìn)程的fpid都是0
第四行輸出是由于迭代到i=1的時(shí)候,當(dāng)前進(jìn)程pid=3224的進(jìn)程第二次執(zhí)行fork函數(shù)產(chǎn)生新的子進(jìn)程pid=3226, 2043-->3224-->3226; 當(dāng)輸出后pid=3224的進(jìn)程結(jié)束了
第五行輸出是由于第一次執(zhí)行fork函數(shù)的時(shí)候產(chǎn)生的子進(jìn)程得到的i=0,還需要執(zhí)行下一次i=1的操作,因此pid=3225也會(huì)產(chǎn)生屬于它的子進(jìn)程,pid=3227,此時(shí)pid=3225的子進(jìn)程相對(duì)于pid=3227的進(jìn)程來(lái)說(shuō),它自己就是父進(jìn)程,3224-->3225-->3227; 當(dāng)輸出后pid=3225的進(jìn)程結(jié)束了
第六行的輸出是來(lái)自于pid=3227的子進(jìn)程,fpid=0;為啥ppid=1呢?而不是3225,因?yàn)?225的進(jìn)程已經(jīng)結(jié)束了,pid = 1是永遠(yuǎn)不會(huì)死亡的
-
第七行的輸出來(lái)自于pid=3226,(由于第二次執(zhí)行fork產(chǎn)生的子進(jìn)程),同上ppid=1(3224的進(jìn)程已經(jīng)結(jié)束了)
