這篇文章介紹的內容包括
1.Linux進程--進程標識號
2.進程控制--進程創建
1.Linux進程--進程標識號
進程(Process)是一個程序在其自身的虛擬地址空間中的一次執行活動。多個程序併發執行,可以提高系統的資源利用率和吞吐量。
進程和程序:
程序只是一個靜態的數據和指令集合,而進程是一個程序的動態執行過程,具有生命週期,是動態的產生和消亡的。
進程是資源申請、調度和獨立運行的單位,因此它使用系統中的運行資源,而程序不佔用系統的運行資源。
程序與進程無一一對應關係。一個程序可以由多個進程所共用,即一個程序在運行過程中可以產生多個進程;一個進程在生命週期內可以順序執行若干個程序。
Linux中的進程,每個進程有一個識別號,PID(Process ID)。系統啓動後的第一個進程是init,PID是1。init是唯一一個由系統內核直接運行的進程。新的進程可以用系統調用fork產生,從一箇舊進程中分出一個新進程來,舊進程是新進程的父進程,新進程是產生他的舊進程的子進程,除了init之外,每一個進程都有父進程。
系統啓動後,init進程會創建login進程等待用戶登錄,當用戶登錄系統後,login進程就會爲用戶啓動shell進程,此後用戶運行的進程都是由shell衍生出來的。
除了PID外,每個進程還有另外4個識別號:
實際用戶識別號(real user ID),
實際組識別號,
有效用戶識別號(effect user ID),
有效組識別號。
實際用戶識別號和實際組識別號用於識別正在運行此進程的用戶和組,也即運行此進程的用戶的識別號和組的識別號。有效用戶識別號和有效組識別號確定一個進程對其訪問的文件的權限和優先權。
2.進程控制--進程創建
所謂控制,就是將進程的一個完整的生命週期(進程的誕生,繁衍與消亡)完全的控制在在程序員的手中。
剛纔提到,在Linux 環境下啓動進程時,系統會自動分配一個唯一的數值給這個進程,這個數值就是這個進程的標識符。
在Linux 中主要的進程標識符有進程號(PID),和它的父進程(PPID)(parents process ID)。PID和PPID都是非零的正整數,在linux中獲得當前的進程PID和PPID的系統調用函數爲getpid和getppid 。
getpid系統調用說明:
所需頭文件 |
#include <unistd.h> |
函數功能: |
取得當前進程的進程號 |
函數原型: |
int getpid(); |
函數傳入值: |
無 |
函數返回 |
成功返回當前進程的進程號,失敗將錯誤包含在perror中 |
備註: |
|
getppid系統調用說明:
所需頭文件 |
#include <unistd.h> |
|
函數功能: |
取得當前進程的父進程號 |
|
函數原型: |
int getppid(); |
|
函數傳入值: |
無 |
|
函數返回 |
成功返回當前進程的父進程號,失敗將錯誤包含在perror中 |
|
備註: |
|
下面給出一個例子顯示進程的標示符和父進程的標示符
- #include <stdio.h>
- #include <unistd.h>
- int main(){
- printf("系統分配的進程號是:%d\n",getpid());
- printf("系統分貝的父進程號是:%d\n",getppid());
- return 0;
- }
進程的創建
fork系統調用
fork系統調用在linux中視最重要的系統調用之一,是我們實現進程控制的最常用的系統調用,並且,很多其他的系統調用也要使用到它!
Fork系統調用說明
所需文件頭: |
#include <unistd> |
函數功能: |
建立一個新進程 |
函數原型: |
Pid_t fork(void); |
函數傳入之值 |
無 |
函數返回值 |
執行成功則建立一個新的進程,在子進程中則返回0,在父進程中回返回新建子進程的進程號(PID),失敗則返回-1 |
備註: |
新進程的信息是複製而來,而非指相同的內存空間,因子進程對這些變量的修改和父進程並不同步。 |
我們知道,進程必須有依託生存的環境,也就是其父進程,每一個進程必須在其父進程的照顧下才能生存,一旦失去其依託的進程,那麼進程就失去了原有的功能,成爲一個即浪費資源,佔用空間而又沒有任何貢獻的行屍走肉——我們叫它——僵死進程。
fork函數的作用是在其進程中創建一個新的進程,這個新的進程不會取代原來的進程,而是以當前進程的一個子進程而存在的。這個子進程會有一個新的進程標識符pid。並且這個子進程會繼承父進程的一切!
什麼是叫繼承父進程的一切呢?就是克隆父進程的所有,包括父進程的代碼,父進程正在執行的狀態,父進程的工作目錄,父進程的所有資源等等,一切的一切,fork系統調用會全部的複製下來。
我們在來看fork函數的返回值,它好像有兩個返回值,其實是一個,在調用fork系統調用後,原先的進程空間從一個變成兩個,而fork函數在不同的進程空間會返回不同的值,在子進程的進程空間中,fork返回 0 ,而在父進程的進程中則返回剛剛新建的子進程的進程標識符,也就是子進程的pid。
下面給出幾個實例
實例1.該實例程序說明fork系統函數執行成功後,生成的子進程從程序中間開始執行程序,此外,還說明父子進程的返回值問題
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- int main()
- {
- pid_t pid;
- printf("Start of fork testing. \n");
- pid=fork();
- printf("Return of fork success:pid=%d\n",pid);
- return 0;
- }
實例2.該程序說明子進程對父進程數據段的繼承性
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #define SIZE 1024
- #define KEY 99
- int shmid;
- int j=5;
- int main()
- {
- int i, *pint;
- pid_t pid;
- char *addr;
- i=10;
- shmid=shmget(SIZE,KEY,IPC_CREAT|0777);
- pint=shmat(shmid,0,0);
- *pint=100;
- printf("Start of fork testing \n");
- pid=fork();
- i++;j++;*pint+=1;
- printf("Return of fork success:pi=%d\n",pid);
- printf("i=%d, j=%d\n",i,j);
- printf("*pint=%d\n",*pint);
- return 0;
- }
實例3.該程序說明fork系統調用後父子進程間共享文件指針的問題,功能爲複製文件
- #include <sys/types.h>
- #include <unistd.h>
- #include <fcntl.h>
- int rfd, wfd;
- char c;
- int main(int argc, char*argv[])
- {
- if(argc!=3)
- {
- printf("Usage %s sourcesfiel destfile. \n",argv[0]);
- return 1;
- }
- if((rfd=open(argv[1], O_RDONLY))==-1)
- {
- printf("openf file %s failed.\n",argv[1]);
- return 2;
- }
- if((wfd=creat(argv[2],0666))==-1)
- {
- printf("create file %s failed.\n",argv[2]);
- return 3;
- }
- fork();
- for(;;)
- {
- if(read(rfd,&c,1)!=1)
- return 1;
- write(wfd,&c,1);
- }
- return 0;
- }
下面,我們將看到一個有意思的東西,但是,這必須建立在我們理解了fork系統調用之後!
我們知道fork會創建子進程,一個和父進程一樣但是完全獨立的子進程。那麼我們下面的代碼:
for(;;) fork();
這是一個無限循環創建子進程的語句,我們想象一下,一旦我們把這樣的語句寫在一個程序中並且執行程序,那麼那個進程就會在無限循環中創建子進程。
那麼系統資源很快就會被不斷創建的子進程佔滿,使系統無法繼續正常工作,那麼,以上就是一個簡單的系統炸彈!
很簡單,一句代碼,你就可以做步入了黑客的殿堂!
當然,這裏真正的黑客還差的很遠,上面的程序破解起來也很簡單,只要系統管理員對用戶可以調用的進程數量進行限制就是破解!
vfork()
創建的子進程結束後需要運行exit()或exec父進程纔會運行,否則就會造成死鎖
下面給出一個簡單的vfork調用
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- int global=4;
- int main()
- {
- pid_t pid;
- int vari=5;
- if((pid=vfork())<0)
- {
- printf("vfork error.\n");
- return 1;
- }
- else if(pid==0)
- {
- global++;
- vari--;
- printf("Child changed the vari and global \n");
- _exit(0);
- }
- else
- printf("Parent didn't changed the vari and global\n");
- printf("global =%d ,vari=%d \n",global,vari);
- return 0;
- }