Linux進程,linux進程查看

來源:互聯網
上載者:User

Linux進程,linux進程查看

Linux進程

進程是Linux中交易管理的基本單元,所有的進程都擁有自己的獨立處理環境和系統資源,並且各進程之間不可以直接存取對方的資源,進程之間的交流需要通過特定的機制(IPC)。

在Linux系統的核心標頭檔中(/usr/src/kernels/核心版本/include/linux/sched.h)定義了進程式控制制塊(PCB)結構體struct task_struct來管理每個進程的資源。

進程資源分為兩個部分:核心空間進程資源、使用者空間進程資源

核心空間進程資源:PCB的相關資訊,控制塊本身、開啟的檔案表項、目前的目錄、當前終端資訊、線程基本資料、可訪問的記憶體空間、PID、PPID、UID、EID等。

使用者進程空間資源:通過成員mm_struct映射的記憶體空間,實際上就是進程的程式碼片段、資料區段、堆、棧、可訪問的共用庫記憶體空間。這些資源在進程退出的時候主動釋放。在進程運行時,可以通過查

看/proc/{pid}/maps檔案查看可以訪問的地址空間。


進程的狀態:就緒、運行、等待(可中斷、不可中斷)、停止、僵死

在/usr/src/kernels/核心版本/include/linux/sched.h標頭檔中定義了進程的狀態

/* * Task state bitmask. NOTE! These bits are also * encoded in fs/proc/array.c: get_task_state(). * * We have two separate sets of flags: task->state * is about runnability, while task->exit_state are * about the task exiting. Confusing, but this way * modifying one set can't modify the other one by * mistake. */#define TASK_RUNNING0#define TASK_INTERRUPTIBLE1#define TASK_UNINTERRUPTIBLE2#define __TASK_STOPPED4#define __TASK_TRACED8/* in tsk->exit_state */#define EXIT_ZOMBIE16#define EXIT_DEAD32/* in tsk->state again */#define TASK_DEAD64#define TASK_WAKEKILL128#define TASK_WAKING256#define TASK_PARKED512#define TASK_STATE_MAX1024

進程之間狀態的轉換圖如下:


進程的屬性

進程本身的屬性:PID(進程號)、PPID(父進程號)、PGID(進程組號)、SID(會話session ID)

調用getpid()函數可以擷取當前進程的PID,該函數在/usr/include/unistd.h標頭檔中聲明;

調用getppid()函數可以擷取當前進程父進程的PID,該函數在/usr/include/unistd.h標頭檔中聲明;

調用getpgid(_pid_t _pid)函數可以擷取指定進程_Pid的進程組號,該函數在/usr/include/unistd.h標頭檔中聲明;

調用getsid(_pid_t _pid)函數可以擷取指定進程_Pid的會話號SID(會話是一個或者多個進程的集合),該函數在/usr/include/unistd.h標頭檔中聲明;


進程的使用者屬性:RUID(真實使用者ID)、RGID(真是使用者組ID)、EUID(有效使用者ID)、EGID(有效使用者組ID)

調用getuid()函數可以擷取該進程的真實使用者RUID(執行此程式的使用者,建立該進程使用者的UID為此進程的RUID),該函數在/usr/include/unistd.h標頭檔中聲明;

調用geteuid()函數可以擷取有效使用者ID,該函數在/usr/include/unistd.h標頭檔中聲明;

調用getgid()擷取進程的使用者組ID(建立進程的使用者所在的組號),該函數在/usr/include/unistd.h標頭檔中聲明;

調用getegid()擷取有效進程使用者組ID,該函數在/usr/include/unistd.h標頭檔中聲明;


進程的管理

建立進程fork 和 vfork

在Linux環境下,建立進程的主要方法是調用fork函數。Linux下的所有進程都是由init進程(第一個進程PID=1)直接或者間接的建立,fork函數在/usr/include/unistd.h標頭檔中聲明;

若fork函數調用,那麼將產生兩個進程分支(父進程和子進程),在父進程中返回子進程的ID(大於0),在子進程中返回0;若調用失敗,在父進程中返回0;

下面是建立調用fork函數的程式

#include<stdio.h>#include<unistd.h>int main(){        pid_t pid;        if( (pid=fork()) == -1 ) //call fork() and test if succeed        {                printf("fork error!");                return -1;        }        else if(pid == 0)  //in sub thread        {                printf("This is sub thread.\n");                printf("in sub : My PID = %d\n",getpid());                printf("in sub : My PPID = %d\n",getppid());        }        else   //in father thread        {                printf("This is father thread.\n");                printf("in father : My PID = %d\n",getpid());        }        return 0;}

子進程與父進程

子進程將複製父進程使用者空間的所有資訊(檔案緩衝區、程式碼片段、資料區段、BSS段、堆、棧、檔案描述符),其中複製的僅僅是檔案描述符,但是對於與檔案描述符關聯的核心檔案表項(struct file結構體)則是採用的是共用的方式。

下面的程式中,雖然子進程複製了父進程的檔案描述符fd,但是和父進程操作的是同一個檔案

#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <stdlib.h>int main(int argc,char *argv[]){    pid_t pid;    int fd;    int i=1;    int status;    char *ch1="hello";    char *ch2="world";    char *ch3="IN";    if((fd=open("test.txt",O_RDWR|O_CREAT,0644))==-1)//開啟一個檔案    {        perror("parent open");        exit(EXIT_FAILURE);    }    if(write(fd,ch1,strlen(ch1))==-1)//父進程向檔案中寫入字串1    {        perror("parent write");        exit(EXIT_FAILURE);    }    if((pid=fork())==-1)//建立一個子進程    {        perror("fork");        exit(EXIT_FAILURE);    }    else if(pid==0)  //在子進程中    {        i=2;        printf("in child\n");        printf("i=%d\n",i);        if(write(fd,ch2,strlen(ch2))==-1)//子進程複製了父進程的fd,然後向檔案中寫入字串2            perror("child write");        return 0;    }    else    {        sleep(1);//休眠1秒鐘,等待子進程執行完畢        printf("in parent\n");        printf("i=%d\n",i);        if(write(fd,ch3,strlen(ch3))==-1)//父進程寫入字串3            perror("parent,write");        wait(&status);//等待子進程結束        return 0;    }}

使用vfork建立進程

使用fork建立進程會複製父進程使用者空間的大量資料,有些情境這樣做是極大的浪費,所以使用vfork建立新進程時並不複製父進程的地址空間,而是在必要的時候才申請新的儲存空間,vfork比fork可以極大程度的提高效能。vfork只在需要的時候覆制,一般採用和父進程共用所有資源的方式處理。

下面的程式說明了vfork建立的子進程和父進程共用資料區段和程式碼片段。

#include<unistd.h>#include<error.h>#include<sys/types.h>#include<stdio.h>#include<stdlib.h>int glob=6;int main(){        int var;        pid_t pid;        var=88;        printf("in beginning:\tglob=%d\tvar=%d\n",glob,var);        if((pid=vfork())<0)        {                perror("vfork");                exit(EXIT_FAILURE);        }        else if(pid==0)        {                printf("in child,modify the var:glob++,var++\n");                glob++;                var++;                printf("in child:\tglob=%d\tvar=%d\n",glob,var);                _exit(0);        }        else        {                printf("in parent:\tglob=%d\tvar=%d\n",glob,var);                return 0;        }}

上述程式共用glob和var變數,如果把上述中的vfork改為fork結果將會不一樣。


結束進程

結束進程意味著要回收進程的資源,又可以分為回收進程使用者空間的資源和回收進程核心空間的資源

回收使用者進程空間的資源

進程在正常退出前都需要執行退出處理函數,重新整理流緩衝區等操作,然後釋放使用者進程空間的所有資源,而進程在核心中的資源PCB並不會立即釋放,僅僅調用退出函數而沒有回收核心資源PCB的進程是一個僵死進程。

顯示的調用exit或者_exit系統調用可以結束進程。調用exit將以反序的方式執行由on_exit函數和atexit函數註冊的清理函數,同時重新整理緩衝區,並把退出狀態status返回給父進程。_exti是直接退出,僅僅把退出狀態交給父進程,不會進行清理工作和重新整理緩衝區。

注意:exit和return的區別,exit退出當前進程,而return僅僅退出當前函數。

回收核心空間的資源

回收核心空間的資源不是由退出進程本身完成的,而是由該進程的父親進程完成的。調用wait函數的父進程將阻塞式的等待該進程的任意一個子進程結束後,回收該子進程的核心空間的資源,wait函數定義在/usr/include/sys/wait.h標頭檔中。還可以使用waitpid函數等待指定子進程結束,其定義在/usr/include/sys/Wait.h中


孤兒進程和僵死進程

孤兒進程:因為父進程退出而導致一個子進程被init進程收養的進程稱為孤兒進程,即孤兒進程的父進程改為init進程。

僵死進程:進程已經退出(使用者空間的資源已經被回收),但是其父親進程還沒有回收核心資源的進程稱為僵死進程,即該進程在核心空間的PCB沒有被釋放。

下面的程式示範了一個孤兒進程

#include<stdio.h>#include<stdlib.h>#include<unistd.h>int main(){        pid_t pid;        if((pid=fork())==-1)                perror("fork");        else if(pid==0)        {                printf("sub : pid=%d,ppid=%d\n",getpid(),getppid());                sleep(2);                printf("sub : pid=%d,ppid=%d\n",getpid(),getppid());        }        else        {                printf("father : pid=%d,ppid=%d\n",getpid(),getppid());                sleep(1);                exit(0);        }}

下面的程式示範了一個僵死進程

#include<stdio.h>#include<unistd.h>#include<stdlib.h>int main(){        pid_t pid;        if((pid=fork())==-1)                perror("fork");        else if(pid==0)        {                printf("child_pid pid=%d\n",getpid());                exit(0);        }        sleep(3);        system("ps");        exit(0);}

程式的運行結果:


運行結果中的PID=10375的進程僵死,如果此時開啟/proc/10375/maps(該進程的使用者進程空間資訊),可以發現為空白,也就是使用者進程空間資源已經被回收。


守護進程

守護進程是一種在後台啟動並執行特殊進程,它脫離終端,從而可以避免守護進程被任何終端訊號打斷,它執行產生的資訊也不在任何終端顯示。守護進程周期性的執行某種任務或等待處理某些發生的事件,Linux的大多數伺服器就是使用守護進程實現的,比如web伺服器httpd等。

一般情況下,守護進程可以通過以下方式啟動:

(1)在系統啟動時啟動指令碼,通常放在/etc/rc.d目錄中;

(2)利用inet超級伺服器啟動,如telnet等;

(3)由cron命令定時啟動以及在終端用nohup命令啟動的進程也是守護進程。


建立一個守護進程需要遵循以下要點:

(1)屏蔽一個有關控制終端操作的訊號

(2)在後台運行。方法是在進程中建立子進程,並使父進程終止,使其在子進程中後台運行。

(3)脫離終端控制和進程組,這是因為一個進程屬於一個進程組,同進程組的進程共用一個控制終端,而一個進程關聯的控制終端和進程組通常是從父進程繼承下來的,因此子進程仍然受到父進程終端的影響。可以使用setsid()使子進程成為一個新的交談群組長和進程組長,與原來的進程組脫離關係。

(4)禁止進程重新開啟控制終端。進程已經成為一個無終端的交談群組長,但是仍然有許可權申請一個終端,只有交談群組長才能開啟終端。採用的辦法是再建立一個子進程,並讓父進程退出,該子進程就不再是交談群組長了,而且父進程也沒有終端控制。

(5)關閉開啟的檔案描述符。子進程會從父進程複製檔案描述符,這對守護進程沒有意義,反而會浪費系統資源,造成進程所佔的檔案系統無法卸載。

(6)改變當前工作目錄。進程活動的時候,進程工作目錄所在的檔案系統不能卸載,因此一般將守護進程的工作目錄設定為合適的目錄。

(7)重設檔案建立的掩碼。進程從父進程那裡繼承檔案建立掩碼umask,它可能修改守護進程所建立的檔案的儲存許可權,一般將檔案建立掩碼清除。

(8)處理SIGCHLD訊號(子進程退出訊號)。





怎查看linux上所有的進程

ps -aux 查看所有進程
top和uptime 可以查看你的系統運行狀態
如果你是想查看具體進程或者說服務的監聽連接埠等
你可以使用 netstat -an | grep ‘你的服務,或者連接埠’ 等
 
LINUX直接殺進程

kill -9 進程號

先 ps -ef | more 看進程情況

如果知道進程名稱 也可以用

ps -ef| grep 進程名稱

找到第二列 就是進程號 ,輸入 kill -9 進程號
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.