程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺談Linux情況下並發編程中C說話fork()函數的應用

淺談Linux情況下並發編程中C說話fork()函數的應用

編輯:關於C++

淺談Linux情況下並發編程中C說話fork()函數的應用。本站提示廣大學習愛好者:(淺談Linux情況下並發編程中C說話fork()函數的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是淺談Linux情況下並發編程中C說話fork()函數的應用正文


由fork創立的新過程被稱為子過程(child process)。fork函數被挪用一次,但前往兩次。子過程的前往值是0,而父過程的前往值則是新過程的過程ID。將子過程ID前往給父過程的來由是:由於一個過程的子過程可以有多個,而且沒有一個函數使一個過程可以取得其一切子過程的過程ID。fork使子過程獲得前往值0的來由是:一個過程只會有一個父過程,所以子過程老是可以挪用getpid以取得其父過程的過程ID。
使fork掉敗的兩個重要緣由是:體系中曾經有了太多的過程,或許該現實用戶ID的過程總數跨越了體系限制。

fork有上面兩種用法:

(1)一個父過程願望復制本身,使父、子過程同時履行分歧的代碼段。這在收集辦事過程中是罕見的--父過程期待客戶真個辦事要求。當這類要求達到時,父過程挪用fork,使子過程處置此要求。父過程則持續期待下一個辦事要求達到。

(2)一個過程要履行一個分歧的法式。這對shell是罕見的情形。子過程從fork前往後立刻挪用exec。

歸結起來講就是是完成多線程。C說話多線程完成須要本身掌握來完成,這個比Java要龐雜。

留意:fork確切創立了一個子過程並完整復制父過程,然則子過程是從fork前面誰人指令開端履行的。關於緣由也很符合邏輯,假如子過程也從main開首到尾履行一切指令,那末它履行到fork指令時也一定會創立一個子子過程,子子孫孫無限盡也,如斯下去,這個小小的法式便可以創立有數多個過程可以把你的電腦弄癱瘓,所以fork作者確定不會這麼做。

本來方才開端做Linux上面的多過程編程的時刻,關於上面這段代碼覺得很奇異,

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdarg.h>
#include<errno.h>
#define LEN 2
void err_exit(char *fmt,...);
int main(int argc,char *argv[])
{
  pid_t pid;
  int loop;

  for(loop=0;loop<LEN;loop++)
  {
  if((pid=fork()) < 0)
    err_exit("[fork:%d]: ",loop);
  else if(pid == 0)
  {
   printf("Child process\n"); 
  }
  else
  {
    sleep(5);
  }
  }

  return 0;
}

為何這段法式會創立3個子過程,而不是兩個,為何在第20行前面加上一個return 0;就創立的又是兩個子過程了?本來一向弄不明確,後來懂得了C說話法式的存儲空間結構和在fork以後父子過程是同享注釋段(代碼段CS)以後才明確這個中的啟事!詳細道理是啥,且容我漸漸道來!

起首得明確一個器械就是C法式的存儲空間結構,以下圖所示:

當一個C法式履行以後,它會被加載到內存當中,它在內存中的結構如上圖,分為這麼幾個部門,情況變量和敕令行參數、棧、堆、數據段(初始化和未初始化的)、注釋段,上面挨個來講明這幾段分離代表了甚麼:

情況變量和敕令行參數:這些指的就是Unix體系上的情況變量(好比$PATH)和傳給main函數的參數(argv指針所指向的內容)。

數據段:這個是指在C法式中界說的全局變量,假如沒有初始化,那末就寄存在未初始化的數據段中,法式運轉時同一由exec賦值為0。不然就寄存在初始化的數據段中,法式運轉時由exec同一從法式文件中讀取。(懂得匯編的同伙們想必曉得匯編說話中的數據段DS,這和匯編中的數據段實際上是一個器械)。

堆:這一部門重要用來靜態分派空間。好比在C說話頂用malloc請求的空間就是在這個區域請求的。

注釋段:C說話代碼其實不是直接履行的,而是被編譯成了機械指令能力夠在電腦上履行,終究生成的機械指令就是寄存在這個區域(匯編中的代碼段CS指的就是這片區域)。

棧:小我感到這是C法式內存結構最症結的部門了。這個部門重要用來做函數挪用。詳細而言怎樣說呢,法式剛開端棧中只要main這一個函數的內容(即main的棧幀),假如main函數要挪用func函數,那末func函數的前往地址(main函數的地址),func函數的參數,func函數中界說的部分變量,還有func函數的前往值等等這些都邑被壓入棧中,這時候棧中就多了func函數的內容(func的棧幀)。然後func函數運轉完了以後再來彈棧,把它本來壓的內容去失落(即消除失落func棧幀),此時棧中又只剩下了main的棧幀。(這片區域就是匯編中的棧段SS)

OK,這就是C法式的存儲器結構。這裡我聯想到別的一點,就是全局變量和靜態變量是存儲在數據段中的,而部分變量是存儲在棧中的,棧中數據在函數挪用完以後一彈棧就沒了,這就是為何全局變量的生計周期比部分變量的生計周期要長的緣由。

懂得了C法式在存儲器的結構以後,我們再來懂得fork的內存復制機制,關於這個,我們只須要懂得一句話就夠了,“子過程復制父過程的數據空間(數據段)、棧和堆,父、子過程同享注釋段。”也就是說,關於法式中的數據,子過程要復制一份,然則關於指令,子過程其實不復制而是和父過程同享。詳細來看上面這段代碼(這是我在下面那段代碼上略微添加了一點器械):

/* 這個法式會創立3個子過程,懂得這句話,父子過程復制數據段、棧、堆,同享注釋段
 *
 */
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdarg.h>
#include<errno.h>
#define BUFSIZE 512
#define LEN 2
void err_exit(char *fmt,...);
int main(int argc,char *argv[])
{
  pid_t pid;
  int loop;

  for(loop=0;loop<LEN;loop++)
  {
  printf("Now is No.%d loop:\n",loop);

  if((pid=fork()) < 0)
    err_exit("[fork:%d]: ",loop);
  else if(pid == 0)
  {
   printf("[Child process]P:%d C:%d\n",getpid(),getppid()); 
  }
  else
  {
    sleep(5);
  }
  }

  return 0;
}

為何下面那段代碼會創立三個子過程?我們來詳細剖析一下它的履行進程:

起首父過程履行輪回,經由過程fork創立一個子過程,然後sleep5秒。

再來看父過程創立的這個子過程,這裡我們記為子過程1.子過程1完整復制了這個父過程的數據部門,然則須要留意的是它的注釋段是和父過程同享的。也就是說,子過程1開端履行代碼的部門其實不是從main的 { 開端履行的,而是主函數履行到哪裡了,它就接著履行,詳細而言就是它會履行fork前面的代碼。所以子過程1起首會打印出它的ID和它的父過程的ID。然後持續第二遍輪回,然後這個子過程1再來創立一個子過程,我們記為子過程11,子過程1開端sleep。

子過程11接著子過程1履行的代碼開端履行(即fork前面),它也是打印出它的ID和父過程ID(子過程1),然後此時loop的值再加1就等於2了,所以子過程2直接就前往了。

誰人子過程1sleep完了以後也是loop的值加1以後釀成了2,所以子過程1也前往了!

然後我們再前往去看父過程,它僅僅輪回了一次,sleep完以後再來停止第二次輪回,此次又創立了一個子過程我們記為子過程2。然後父過程開端sleep,sleep完了以後也停止了。

那末誰人子過程2怎樣樣了呢?它從fork後開端履行,此時loop等於1,它打印完它的ID和父過程ID以後,就停止輪回了,全部子過程2就直接停止了!

這就是下面那段代碼的運轉流程,過程間的關系以下圖所示:

上圖中誰人loop=%d就是當這個過程開端履行的時刻loop的值。下面那段代碼的運轉成果以下圖:

這裡這個3498過程就是我們的主過程,3499就是子過程1,3500就是子過程11,3501就是子過程2。

最初,我們再往返答一下我們開端的時刻提出的誰人成績,為何在子過程的處置部門“ if(pid == 0) ”最初加一個return 0,就會創立兩個子過程了,就是由於子過程1運轉到這裡直接就停止了,不再停止第二遍輪回了,所以就不會再去創立誰人子過程11了,所以最初一共就是創立了兩個子過程啊!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved