Linux多進程


一、進程的概念

什么是進程?進程這個概念是針對系統而不是針對程序員的,對程序員來說,我們面對的概念是程序,當輸入指令執行一個程序的時候,對系統而言,它將啟動一個進程。

進程就是正在內存中運行中的程序,Linux下一個進程在內存里有三部分的數據,就是“代碼段”、”堆棧段”和”數據段”。”代碼段”,顧名思義,就是存放了程序代碼。“堆棧段”存放的就是程序的返回地址、程序的參數以及程序的局部變量。而“數據段”則存放程序的全局變量,常數以及動態數據分配的數據空間(比如用new函數分配的空間)。

系統如果同時運行多個相同的程序,它們的“代碼段”是相同的,“堆棧段”和“數據段”是不同的(相同的程序,處理的數據不同)。

二、進程的編號

1、查看進程

ps 查看當前終端的進程。

在這里插入圖片描述

ps -ef 查看系統全部的進程。

ps -ef |more 查看系統全部的進程,結果分頁顯示。

在這里插入圖片描述

UID :啟動進程的操作系統用戶。

PID :進程編號。

PPID :進程的父進程的編號。

C :CPU使用的資源百分比。

STIME :進程啟動時間。

TTY :進程所屬的終端。

TIME :使用掉的CPU時間。

CMD :執行的是什么指令。

ps -ef |grep book查看系統全部的進程,然后從結果集中過濾出包含“book”單詞的記錄。程序員用得最多的指令就是這個了。

在這里插入圖片描述

2、getpid庫函數

getpid庫函數的功能是獲取本程序運行時進程的編號。

函數聲明:

pid_t getpid();

函數沒有參數,返回值是進程的編號,pid_t就是typedef int pid_t。

示例(book251.cpp)

/*
 * 程序名:book251.cpp,此程序用於演示獲取程序運行時的進程編號
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  printf("本程序的進程編號是:%d\n",getpid());
  sleep(30);    // 是為了方便查看進程在shell下用ps -ef|grep book251查看本進程的編號。
}

運行效果

在這里插入圖片描述

在book251運行時,切換到其它的窗口,執行ps -ef|grep book251可以查看進程,如下。

在這里插入圖片描述

注意兩個細節:

1)進程的編號是系統動態分配的,相同的程序在不同的時間執行,進程的編號是不同的。

2)進程的編號會循環使用,但是,在同一時間,進程的編號是唯一的,也就是說,不管任何時間,系統不可能存在兩個編號相同的進程。

三、多進程

fork在英文中是“分叉”的意思。為什么取這個名字呢?因為一個進程在運行中,如果使用了fork函數,就產生了另一個進程,於是進程就“分叉”了,所以這個名字取得很形象。下面就看看如何具體使用fork函數,這段程序演示了使用fork的基本框架。

函數聲明:

pid_t fork();

fork函數用於產生一個新的進程,函數返回值pid_t是一個整數,在父進程中,返回值是子進程編號,在子進程中,返回值是0。

示例(book252.cpp)

/*
 * 程序名:book252.cpp,此程序用於演示用fork生成一個子進程。
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  printf("本程序的進程編號是:%d\n",getpid());

  int ipid=fork();

  sleep(1);       // sleep等待進程的生成。

  printf("pid=%d\n",ipid);

  if (ipid!=0) printf("父進程編號是:%d\n",getpid());
  else printf("子進程編號是:%d\n",getpid());

  sleep(30);    // 是為了方便查看進程在shell下用ps -ef|grep book252查看本進程的編號。
}

運行效果

在這里插入圖片描述

查看進程情況,出現了兩個book進程。

在這里插入圖片描述
初學者可能用點接受不了現實。

1)一個函數(fork)返回了兩個值?

2)if和else中的代碼能同時被執行?

那么調用這個fork函數時發生了什么呢?fork函數創建了一個新的進程,新進程(子進程)與原有的進程(父進程)一模一樣。子進程和父進程使用相同的代碼段;子進程拷貝了父進程的堆棧段和數據段。子進程一旦開始運行,它復制了父進程的一切數據,然后各自運行,相互之間沒有影響。

fork函數對返回值做了特別的處理,調用fork函數之后,在子程序中fork的返回值是0,在父進程中fork的返回值仍是原進程的編號,程序員可以通過fork的返回值來區分父進程和子進程,然后再執行不同的代碼。

示例(book253.cpp)

/*
 * 程序名:book253.cpp,此程序用於演示用fork生成一個子進程后,父子進程進入不同的流程。
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

void fatchfunc()  // 父進程流程的主函數
{
  printf("我是老子,我喜歡孩子他娘。\n");
}

void childfunc()  // 子進程流程的主函數
{
  printf("我是兒子,我喜歡西施。\n");
}

int main()
{
  if (fork()>0) { printf("這是父進程,將調用fatchfunc()。\n"); fatchfunc();}
  else { printf("這是子進程,將調用childfunc()。\n");  childfunc();}

  sleep(1); printf("父子進程執行完自己的函數后都來這里。\n"); sleep(1);
}

運行效果

在這里插入圖片描述

在上文上已提到過,子進程拷貝了父進程的堆棧段和數據段,也就是說,在父進程中定義的變量子進程中會復制一個副本,fork之后,子進程對變量的操作不會影響交父進程,父進程對變量的操作也不會影響子進程。

示例(book254.cpp)

/*
 * 程序名:book254.cpp,此程序用於演示用fork之后的父子進程在內存中是獨立的數據空間。
 * 作者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int ii=10;

int main()
{
  int jj=20;

  if (fork()>0) 
  { 
    ii=11;jj=21; sleep(1);  printf("父進程:ii=%d,jj=%d\n",ii,jj);
  }
  else
  { 
    ii=12;jj=22; sleep(1);  printf("子進程:ii=%d,jj=%d\n",ii,jj);
  }
}

運行效果

在這里插入圖片描述

四、課后作業

1)編寫一個多進程程序,驗證子進程是復制父進程的內存變量,還是父子進程共享內存變量?

2)編寫一個示例程序,由父進程生成10個子進程,在子進程中顯示它是第幾個子進程和子進程本身的進程編號。

3)編寫示例程序,由父進程生成子進程,子進程再生成孫進程,共生成第10代進程,在各級子進程中顯示它是第幾代子進程和子進程本身的進程編號。

4)利用盡可能少的代碼快速fork出更多的進程,試試看能不能把linux系統搞死。

5)ps -ef |grep book251命令是ps和grep兩個系統命令的組合,各位查一下資料,了解一下grep命令的功能,對程序員來,grep是經常用到的命令。

五、版權聲明

C語言技術網原創文章,轉載請說明文章的來源、作者和原文的鏈接。
來源:C語言技術網(www.freecplus.net)
作者:碼農有道

如果文章有錯別字,或者內容有錯誤,或其他的建議和意見,請您留言指正,非常感謝!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM