一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

fork后子進(jìn)程從哪里開(kāi)始執(zhí)行

 紫火神兵 2012-09-27

出處:http://hi.baidu.com/okeyes888/item/14559ae22eb72da9ce2d4f04

加自己的修改?。ùa驗(yàn)證)

 

fork確實(shí)創(chuàng)建了一個(gè)子進(jìn)程并完全復(fù)制父進(jìn)程,但是子進(jìn)程是從fork后面那個(gè)指令開(kāi)始執(zhí)行的。
對(duì)于原因也很合邏輯,如果子進(jìn)程也從main開(kāi)頭到尾執(zhí)行所有指令,那它執(zhí)行到fork指令時(shí)也必定會(huì)創(chuàng)建一個(gè)子子進(jìn)程,如此下去這個(gè)小小的程序就可以創(chuàng)建無(wú)數(shù)多個(gè)進(jìn)程可以把你的電腦搞癱瘓,所以fork作者肯定不會(huì)傻到這種程度

fork和線程,進(jìn)程的理解2011-10-11 10:09

本文分為三部分:

1.       什么是fork?

2.       fork用途?

3.       fork怎么工作?

 

1.  什么是fork?

Fork源于OS中多線程任務(wù)的需要。在傳統(tǒng)的Unix環(huán)境下,有兩個(gè)基本的操作用于創(chuàng)建和修改進(jìn)程:函數(shù)fork( )用來(lái)創(chuàng)建一個(gè)新的進(jìn)程,該進(jìn)程幾乎是當(dāng)前進(jìn)程的一個(gè)完全拷貝;函數(shù)族e(cuò)xec( )用來(lái)啟動(dòng)另外的進(jìn)程以取代當(dāng)前運(yùn)行的進(jìn)程。

下面說(shuō)一下進(jìn)程和線程。

進(jìn)程的簡(jiǎn)單理解就是:一個(gè)進(jìn)程表示的就是一個(gè)可執(zhí)行程序的一次執(zhí)行過(guò)程中的一個(gè)狀態(tài)。

一個(gè)進(jìn)程,主要包含三個(gè)元素:

一個(gè)可以執(zhí)行的程序; --- 代碼段
和該進(jìn)程相關(guān)聯(lián)的全部數(shù)據(jù)(包括變量,內(nèi)存空間,緩沖區(qū)等等); --- 數(shù)據(jù)段
程序的執(zhí)行上下文(execution context)。 --- 堆棧段

   

 "代碼段",顧名思義,就是存放了程序代碼的數(shù)據(jù),假如機(jī)器中有數(shù)個(gè)進(jìn)程運(yùn)行相同的一個(gè)程序,那么它們就可以使用相同的代碼段。

"堆棧段"存放的就是子程序的返回地址、子程序的參數(shù)以及程序的局部變量。

數(shù)據(jù)段則存放程序的全局變量,常數(shù)以及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間(比如用malloc之類的函數(shù)取得的空間)。

 

 

一般的CPU都有上述三種段寄存器,以方便操作系統(tǒng)的運(yùn)行。這三個(gè)部分也是構(gòu)成一個(gè)完整的執(zhí)行序列的必要的部分。系統(tǒng)如果同時(shí)運(yùn)行數(shù)個(gè)相同的程序,它們之間就不能使用同一個(gè)堆棧段和數(shù)據(jù)段。  

    操作系統(tǒng)對(duì)進(jìn)程管理,最典型的是通過(guò)進(jìn)程表完成的。進(jìn)程表里再通過(guò)一個(gè)稱為“程序計(jì)數(shù)器(program counter, pc)”的寄存器來(lái)完成“上下文的切換”。(實(shí)際的上下文交換需要涉及到更多的數(shù)據(jù),和fork無(wú)關(guān),不再多說(shuō),PC主要用于指出程序當(dāng)前已經(jīng)執(zhí)行到哪里,是進(jìn)程上下文的重要內(nèi)容,換出CPU的進(jìn)程要保存這個(gè)寄存器的值,換入CPU的進(jìn)程,也要根據(jù)進(jìn)程表中保存的本進(jìn)程執(zhí)行上下文信息,更新這個(gè)寄存器)。

    進(jìn)程表中的每一個(gè)表項(xiàng),記錄的是當(dāng)前操作系統(tǒng)中一個(gè)進(jìn)程的情況。對(duì)于單 CPU的情況而言,每一特定時(shí)刻只有一個(gè)進(jìn)程占用 CPU,但是系統(tǒng)中可能同時(shí)存在多個(gè)活動(dòng)的(等待執(zhí)行或繼續(xù)執(zhí)行的)進(jìn)程。
        PC用于指出當(dāng)前占用 CPU的進(jìn)程要執(zhí)行的下一條指令的位置。 當(dāng)分給某個(gè)進(jìn)程的 CPU時(shí)間已經(jīng)用完,操作系統(tǒng)將該進(jìn)程相關(guān)的寄存器的值,保存到該進(jìn)程在進(jìn)程表中對(duì)應(yīng)的表項(xiàng)里面;把將要接替這個(gè)進(jìn)程占用 CPU的那個(gè)進(jìn)程的上下文,從進(jìn)程表中讀出,并更新相應(yīng)的寄存器(這個(gè)過(guò)程稱為“上下文交換(process context switch)”

 

 

    下面繼續(xù)說(shuō)fork了。當(dāng)程序執(zhí)行到下面的語(yǔ)句:pid=fork();  操作系統(tǒng)創(chuàng)建一個(gè)新的進(jìn)程(子進(jìn)程),并且在進(jìn)程表中相應(yīng)為它建立一個(gè)新的表項(xiàng)。新進(jìn)程和原有進(jìn)程的可執(zhí)行程序是同一個(gè)程序;上下文和數(shù)據(jù),絕大部分就是原進(jìn)程(父進(jìn)程)的拷貝,但它們是兩個(gè)相互獨(dú)立的進(jìn)程!此時(shí)程序寄存器pc,在父、子進(jìn)程的上下文中都聲稱,這個(gè)進(jìn)程目前執(zhí)行到fork調(diào)用即將返回(此時(shí)子進(jìn)程不占有CPU,子進(jìn)程的pc不是真正保存在寄存器中,而是作為進(jìn)程上下文保存在進(jìn)程表中的對(duì)應(yīng)表項(xiàng)內(nèi))。問(wèn)題是怎么返回。它們的返回順序是不確定的,取決于OS內(nèi)的調(diào)度。如果想明確它們的執(zhí)行順序,就得實(shí)現(xiàn)“同步”,或者是使用vfork()。這里假設(shè)父進(jìn)程繼續(xù)執(zhí)行,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn),使這個(gè)調(diào)用在父進(jìn)程中返回剛剛創(chuàng)建的子進(jìn)程的pid(一個(gè)正整數(shù)),所以下面的if語(yǔ)句中pid<0, pid==0的兩個(gè)分支都不會(huì)執(zhí)行。所以一般執(zhí)行fork后都會(huì)有兩個(gè)輸出。

   

2.  Fork用途歸結(jié)起來(lái)有兩個(gè):

第一,   一個(gè)進(jìn)程希望復(fù)制自身,從而父子進(jìn)程能執(zhí)行不同代碼段。

第二,   進(jìn)程想執(zhí)行另外一個(gè)程序

歸結(jié)起來(lái)說(shuō)就是實(shí)現(xiàn)多線程。C語(yǔ)言多線程實(shí)現(xiàn)需要自己控制來(lái)實(shí)現(xiàn),這個(gè)比JAVA要復(fù)雜。

 

3.  Fork怎么工作?先看一個(gè)例子:

#include <unistd.h>;

#include <sys/types.h>;

int main ()

{

       pid_t pid;

          pid=fork();  // 1)從這里開(kāi)始程序分岔,父子進(jìn)程都從這一句開(kāi)始執(zhí)行一次

          if (pid < 0)

                  printf("error!");

          else if (pid == 0)

                  printf("child process, process id is %dn", getpid());

          else // pid > 0

                  printf("parent process, process id is %dn",getpid()); 

          return 0;

}

結(jié)果:

[root@localhost yezi]# ./a.out 
child process, process id is 4286   //這里為什么會(huì)打印兩結(jié)果呢?后面會(huì)解釋
parent process, process id is 4285  

 

 

對(duì)于上面程序段有以下幾個(gè)關(guān)鍵點(diǎn):

 

(1)返回值的問(wèn)題:

正確返回:父進(jìn)程中返回子進(jìn)程的pid,因此> 0;子進(jìn)程返回0
錯(cuò)誤返回:-1

     子進(jìn)程是父進(jìn)程的一個(gè)拷貝。即,子進(jìn)程從父進(jìn)程得到了數(shù)據(jù)段和堆棧段的拷貝,這些需要分配新的內(nèi)存;而對(duì)于只讀的代碼段,通常使用共享內(nèi)存的方式訪問(wèn)。父進(jìn)程與子進(jìn)程的不同之處在于:fork的返回值不同——父進(jìn)程中的返回值為子進(jìn)程的進(jìn)程號(hào),而子進(jìn)程為0。只有父進(jìn)程執(zhí)行的getpid()才是他自己的進(jìn)程號(hào)。對(duì)子進(jìn)程來(lái)說(shuō),fork返回給它0,但它的pid絕對(duì)不會(huì)是0;之所以fork返回0給它,是因?yàn)樗S時(shí)可以調(diào)用getpid()來(lái)獲取自己的pid;

 

(2) fork返回后,子進(jìn)程和父進(jìn)程都從調(diào)用fork函數(shù)的下一條語(yǔ)句開(kāi)始執(zhí)行。這也是程序中會(huì)打印兩個(gè)結(jié)果的原因。

     fork之后,操作系統(tǒng)會(huì)復(fù)制一個(gè)與父進(jìn)程完全相同的子進(jìn)程。不過(guò)這在操作系統(tǒng)看來(lái),他們更像兄弟關(guān)系,這2個(gè)進(jìn)程共享代碼空間,但是數(shù)據(jù)空間是互相獨(dú)立的,子進(jìn)程數(shù)據(jù)空間中的內(nèi)容是父進(jìn)程的完整拷貝,指令指針也完全相同,但只有一點(diǎn)不同,如果fork成功,子進(jìn)程中fork的返回值是0,父進(jìn)程中fork的返回值是子進(jìn)程的進(jìn)程號(hào),如果fork不成功,父進(jìn)程會(huì)返回錯(cuò)誤。2個(gè)進(jìn)程一直同時(shí)運(yùn)行,而且步調(diào)一致,在fork之后,他們分別作不同的工作,也就是分岔了。這也是fork為什么叫fork的原因。至于哪一個(gè)先運(yùn)行,與操作系統(tǒng)的調(diào)度算法有關(guān),而且這個(gè)問(wèn)題在實(shí)際應(yīng)用中并不重要,如果需要父子進(jìn)程協(xié)同,可以通過(guò)原語(yǔ)的辦法實(shí)現(xiàn)同步來(lái)加以解決。

    為了加深理解,看下面例子:

#include <stdio.h>
#include "../include/apue.h"
#include <unistd.h>

int main()
{
        pid_t    a_pid, b_pid;
        if((a_pid=fork())<0)  // // 一定要有紅色括號(hào)??! 沒(méi)有的話就a_pid永遠(yuǎn)等于0,則永遠(yuǎn)不會(huì)執(zhí)行父進(jìn)程?。。?br>
                printf("error!");
        else if(a_pid==0)
        {
                printf("the first child's pid=%d\n",getpid());
                printf("b\n");
        }
        else
        {
                printf("the parent's pid=%d\n",getpid());
                printf("a\n");
        }


        if((b_pid=fork())<0)
                printf("error!");
        else if(b_pid==0)
        {
                printf("c\n");
        }
        else
        {
                printf("e\n");
        }
        return 0;
}

 

 

輸出的結(jié)果:   

(1)

the first child's pid=12623
b
c
e
the parent's pid=12622
a
c
e

 

(2)

the first child's pid=12638
b
the parent's pid=12637
a
c
e
c
e

 

(3)

the first child's pid=12642
b
the parent's pid=12641
a
c
c
e
e

 

很奇妙的結(jié)果。不過(guò)理解了“子進(jìn)程和父進(jìn)程都從調(diào)用fork函數(shù)的下一條語(yǔ)句開(kāi)始執(zhí)行”了也不奇怪了。同是這里引入理解fork的第三點(diǎn)

 

(3) fork函數(shù)不同于其他函數(shù),在于它可能會(huì)有兩個(gè)或是多個(gè)返回值,而且是同時(shí)返回兩個(gè)值。繼續(xù)分析上面的例子。

    理解上例的關(guān)鍵在于fork()的返回點(diǎn)在哪里。Fork()同時(shí)返回兩個(gè)值。其中pid=0的這個(gè)返回值用來(lái)執(zhí)行子進(jìn)程的代碼,而大于0的一個(gè)返回值為父進(jìn)程的代碼塊。第一次fork調(diào)用的時(shí)候生叉分為兩個(gè)進(jìn)程,假設(shè)為a父進(jìn)程和b子進(jìn)程。他們分別各自在第二次fork調(diào)用之前打印了b和a各一次;在第一次叉分的這兩個(gè)進(jìn)程中都含有   


   if(b_pid=fork()<0)   // 一定要有紅色括號(hào)??! 沒(méi)有的話就b_pid永遠(yuǎn)等于0
   {   
          printf("error!");   
   }   
   else if(b_pid==0)   
        printf("c/n");   
   else   
        printf("e/n");  

   
      這段代碼。很明顯,a父進(jìn)程和b子進(jìn)程在這段代碼中又各自獨(dú)立的被叉分為兩個(gè)進(jìn)程。這兩個(gè)進(jìn)程每個(gè)進(jìn)程又都打印了e,c各一次。到此,在程序中總共打印兩次c,e和一次a,b??偣?個(gè)字母。   
      注:在第一次叉分為兩個(gè)進(jìn)程的時(shí)候父子進(jìn)程含有完全相同的代碼(第二次仍然相同),只是因?yàn)樵诟缸舆M(jìn)程中返回的PID的值不同,父進(jìn)程代碼中的PID的值大于0,子進(jìn)程代碼中的值等于0,從而通過(guò)if這樣的分支選擇語(yǔ)句來(lái)執(zhí)行各自的任務(wù)。

    當(dāng)然在使用fork中還有很多細(xì)節(jié),比如輸出時(shí),對(duì)緩沖區(qū)的不同處理會(huì)使父子進(jìn)程執(zhí)行過(guò)程中輸出不同,以及fork后,子進(jìn)程的exec和exit的一些實(shí)現(xiàn)細(xì)節(jié)。以后再說(shuō)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日韩人妻毛片中文字幕| 黑丝袜美女老师的小逼逼| 九九视频通过这里有精品| 91日韩欧美国产视频| 亚洲熟妇av一区二区三区色堂| 日韩国产亚洲欧美另类| 精品日韩av一区二区三区| 人妻久久这里只有精品| 黄色三级日本在线观看| 国产一区一一一区麻豆| 久久re6热在线视频| 亚洲欧美日韩在线中文字幕| 精品久久久一区二区三| 夫妻性生活动态图视频| 夜色福利久久精品福利| 狠狠做深爱婷婷久久综合| 精品日韩av一区二区三区| 欧美午夜不卡在线观看| 欧美国产日韩变态另类在线看| 婷婷九月在线中文字幕| 国产亚洲欧美另类久久久| 日韩国产亚洲欧美激情| 一区二区在线激情视频| 最好看的人妻中文字幕| 欧美大胆美女a级视频| 国产欧美日韩精品一区二区| 日韩一区中文免费视频| 久久国产人妻一区二区免费| 久久综合狠狠综合久久综合| 欧美性猛交内射老熟妇| 偷拍美女洗澡免费视频| 国产成人国产精品国产三级| 丰满人妻少妇精品一区二区三区| 91人人妻人人爽人人狠狠| 91播色在线免费播放| 91偷拍裸体一区二区三区| 黑人巨大精品欧美一区二区区 | 高清不卡一卡二卡区在线| 99国产高清不卡视频| 邻居人妻人公侵犯人妻视频| 国产成人精品综合久久久看|