操作系統(tǒng)fork函數(shù)

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é)束了)


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容