IT貓撲網(wǎng):您身邊最放心的安全下載站! 最新更新|軟件分類|軟件專題|手機(jī)版|論壇轉(zhuǎn)貼|軟件發(fā)布

您當(dāng)前所在位置: 首頁操作系統(tǒng)LINUX → Linux系統(tǒng)調(diào)用fork()用法詳解

Linux系統(tǒng)調(diào)用fork()用法詳解

時(shí)間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評(píng)論(0)

  這學(xué)期在學(xué)操作系統(tǒng),老師布置了一個(gè)關(guān)于進(jìn)程的實(shí)驗(yàn)題,是在Linux系統(tǒng)中實(shí)現(xiàn)的,其中有涉及到fork()函數(shù)的調(diào)用,恰好我研究Ubuntu 也有一段時(shí)間了,就了解了下fork()函數(shù),下面把自己實(shí)驗(yàn)的一點(diǎn)心得貼上來,也希望能幫到各位初學(xué)者(我也是個(gè)初學(xué)者)。

  先看下我在網(wǎng)上搜索到的一篇文章,至于原作者找不到了,望諒解。如下:

  1. 先看下面代碼:

  #include

  #include ??? //pid_t類型定義

  #include ? //函數(shù)fork(),getpid()定義

  void main ()

  {

  pid_t pid;

  pid=fork();

  if (pid < 0)

  printf("error in fork!");

  else if (pid == 0)

  printf("i am the child process, my process id is %d\n",getpid());

  else

  printf("i am the parent process, my process id is %d\n",getpid());

  }

  要搞清楚fork的執(zhí)行過程,就必須先講清楚操作系統(tǒng)中的"進(jìn)程(process)"概念。

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

  o. 一個(gè)可以執(zhí)行的程序;

  o. 和該進(jìn)程相關(guān)聯(lián)的全部數(shù)據(jù)(包括變量,內(nèi)存空間,緩沖區(qū)等等);

  o. 程序的執(zhí)行上下文(execution context)。

  不妨簡(jiǎn)單理解為,一個(gè)進(jìn)程表示的就是一個(gè)可執(zhí)行程序的一次執(zhí)行過程中的一個(gè)狀態(tài)。操作系統(tǒng)對(duì)進(jìn)程的管理,典型的情況,是通過進(jìn)程表完成的。進(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)程。

  一個(gè)稱為"程序計(jì)數(shù)器(program counter, 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è)過程稱為"上下文交換(process context switch)",實(shí)際的上下文交換需要涉及到更多的數(shù)據(jù),那和fork無關(guān),不再多說,主要要記住程序寄存器pc指出程序當(dāng)前已經(jīng)執(zhí)行到哪里,是進(jìn)程上下文的重要內(nèi)容,換出 CPU的進(jìn)程要保存這個(gè)寄存器的值,換入CPU的進(jìn)程,也要根據(jù)進(jìn)程表中保存的本進(jìn)程執(zhí)行上下文信息,更新這個(gè)寄存器)。

  好了,有這些概念打底,可以說fork了。當(dāng)你的程序執(zhí)行到下面的語句:

  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))。問題是怎么返回,在父子進(jìn)程中就分道揚(yáng)鑣。

  父進(jìn)程繼續(xù)執(zhí)行,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn)是,這個(gè)調(diào)用在父進(jìn)程中返回剛剛創(chuàng)建的子進(jìn)程的pid(一個(gè)正整數(shù)),所以下面的if語句中pid<0, pid==0的兩個(gè)分支都不會(huì)執(zhí)行。所以輸出i am the parent process...子進(jìn)程在之后的某個(gè)時(shí)候得到調(diào)度,它的上下文被換入,占據(jù) CPU,操作系統(tǒng)對(duì)fork的實(shí)現(xiàn),使得子進(jìn)程中fork調(diào)用返回0。所以在這個(gè)進(jìn)程(注意這不是父進(jìn)程了哦,雖然是同一個(gè)程序,但是這是同一個(gè)程序的另外一次執(zhí)行,在操作系統(tǒng)中這次執(zhí)行是由另外一個(gè)進(jìn)程表示的,從執(zhí)行的角度說和父進(jìn)程相互獨(dú)立)中pid=0,所以輸出 i am the child process...

  我想你比較困惑的就是,為什么看上去程序中互斥的兩個(gè)分支都被執(zhí)行了。在一個(gè)程序的一次執(zhí)行中,這當(dāng)然是不可能的;但是你看到的兩行輸出是來自兩個(gè)進(jìn)程,這兩個(gè)進(jìn)程來自同一個(gè)程序的兩次執(zhí)行。

  下面是我的一點(diǎn)心得,關(guān)于子進(jìn)程的調(diào)用點(diǎn)問題,如下:

  2. 子進(jìn)程的調(diào)用點(diǎn)詳解

  子進(jìn)程是從fork()函數(shù)開始執(zhí)行的。范例:

  #include

  #include ??? //pid_t類型定義

  #include ? //函數(shù)fork(),getpid()定義

  void main()

  {

  pid_t p1,p2;

  p1=fork();

  if(p1<0)

  printf("error in fork!");

  else if (p1 == 0)

  printf("child process pid: %d\n",getpid());

  else

  printf("parent process pid: %d\n",getpid());

  p2=fork();

  if(p2<0)

  printf("error in fork!");

  else if (p2 == 0)

  printf("child process pid: %d\n",getpid());

  else

  printf("parent process pid: %d\n",getpid());

  }

#p#副標(biāo)題#e#

  上述程序的編譯執(zhí)行結(jié)果如下:

  jenner@Intrepid:~/Desktop$ gcc 01.c -o 01

  jenner@Intrepid:~/Desktop$ ./01

  child process pid: 14844

  child process pid: 14845

  parent process pid: 14844

  parent process pid: 14843

  child process pid: 14846

  parent process pid: 14843

  注釋:最初的43號(hào)進(jìn)程執(zhí)行兩個(gè)fork(),輸出兩個(gè)parent43,并產(chǎn)生子進(jìn)程44號(hào)和45號(hào);

  44號(hào)進(jìn)程從第一個(gè)fork()函數(shù)開始執(zhí)行,輸出child44,調(diào)用第二個(gè)fork(),輸出parent44,并產(chǎn)生子進(jìn)程46號(hào);

  45號(hào)進(jìn)程從第二個(gè)fork()函數(shù)開始執(zhí)行,輸出child45;

  46號(hào)進(jìn)程從第二個(gè)fork()函數(shù)開始執(zhí)行,輸出child46;

  至此程序結(jié)束。

  注意:以上過程不是程序的先后運(yùn)行過程,那六個(gè)輸出的先后順序是不確定的!

  程序中所有進(jìn)程的父子關(guān)系如下:

  父進(jìn)程43? ---子進(jìn)程44

  ---子進(jìn)程的子進(jìn)程46

  ---子進(jìn)程45

  其中44號(hào)進(jìn)程既是43號(hào)進(jìn)程的子進(jìn)程,又是46號(hào)進(jìn)程的父進(jìn)程。

  以上是我的一些心得,看著可能有點(diǎn)繞口,耐心點(diǎn),我也研究了好久呢,如果你看懂了,fork()函數(shù)也就算基本理解了!

  順便也把老師布置的作業(yè)題也貼上來吧,呵呵,如下:

  3. 題目:進(jìn)程的創(chuàng)建:編制一段程序,使用系統(tǒng)調(diào)用fork( )創(chuàng)建兩個(gè)子進(jìn)程,這樣在此程序運(yùn)行時(shí),在系統(tǒng)中就有一個(gè)父進(jìn)程和兩個(gè)子進(jìn)程在活動(dòng)。讓每一個(gè)進(jìn)程在屏幕上顯示一個(gè)字符:父進(jìn)程顯示字符a,子進(jìn)程分別顯示字符 b和字符c。試觀察、記錄并分析屏幕上,進(jìn)程調(diào)度的情況。

  代碼如下:

  #include

  #include

  #include

  void main()

  {

  pid_t p1,p2;

  p1=fork();

  if(p1<0)

  printf("error in fork!\n");

  else if (p1 == 0)

  printf("child process b\n");

  else

  {

  p2=fork();

  if(p2<0)

  printf("error in fork!\n");

  else if (p2 == 0)

  printf("child process c\n");

  else

  printf("parent process a\n");

  }

  }

關(guān)鍵詞標(biāo)簽:Linux

相關(guān)閱讀

文章評(píng)論
發(fā)表評(píng)論

熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP Linux操作系統(tǒng)修改IP

相關(guān)下載

    人氣排行 Linux下獲取CPUID、硬盤序列號(hào)與MAC地址 dmidecode命令查看內(nèi)存型號(hào) linux tc實(shí)現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機(jī)、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負(fù)載