Centos進程狀態(tài)怎么看

本篇內(nèi)容介紹了“Centos進程狀態(tài)怎么看”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

本篇內(nèi)容介紹了“Centos進程狀態(tài)怎么看”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

10年積累的做網(wǎng)站、網(wǎng)站設(shè)計經(jīng)驗,可以快速應對客戶對網(wǎng)站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站策劃后付款的網(wǎng)站建設(shè)流程,更有橋東免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

眾所周知,現(xiàn)在的分時操作系統(tǒng)能夠在一個CPU上運行多個程序,讓這些程序表面上看起來是在同時運行的。linux就是這樣的一個操作系統(tǒng)。

在linux系統(tǒng)中,每個被運行的程序?qū)嵗龑粋€或多個進程。linux內(nèi)核需要對這些進程進行管理,以使它們在系統(tǒng)中“同時”運行。linux內(nèi)核對進程的這種管理分兩個方面:進程狀態(tài)管理,和進程調(diào)度。

進程狀態(tài)

在linux下,通過ps命令我們能夠查看到系統(tǒng)中存在的進程,以及它們的狀態(tài):R

 (TASK_RUNNING),可執(zhí)行狀態(tài)。

只有在該狀態(tài)的進程才可能在CPU上運行。而同一時刻可能有多個進程處于可執(zhí)行狀態(tài),這些進程的task_struct結(jié)構(gòu)(進程控制塊)被放入對應CPU的可執(zhí)行隊列中(一個進程最多只能出現(xiàn)在一個CPU的可執(zhí)行隊列中)。進程調(diào)度器的任務(wù)就是從各個CPU的可執(zhí)行隊列中分別選擇一個進程在該CPU上運行。

只要可執(zhí)行隊列不為空,其對應的CPU就不能偷懶,就要執(zhí)行其中某個進程。一般稱此時的CPU“忙碌”。對應的,CPU“空閑”就是指其對應的可執(zhí)行隊列為空,以致于CPU無事可做。

有人問,為什么死循環(huán)程序會導致CPU占用高呢?因為死循環(huán)程序基本上總是處于TASK_RUNNING狀態(tài)(進程處于可執(zhí)行隊列中)。除非一些非常極端情況(比如系統(tǒng)內(nèi)存嚴重緊缺,導致進程的某些需要使用的頁面被換出,并且在頁面需要換入時又無法分配到內(nèi)存……),否則這個進程不會睡眠。所以CPU的可執(zhí)行隊列總是不為空(至少有這么個進程存在),CPU也就不會“空閑”。

很多操作系統(tǒng)教科書將正在CPU上執(zhí)行的進程定義為RUNNING狀態(tài)、而將可執(zhí)行但是尚未被調(diào)度執(zhí)行的進程定義為READY狀態(tài),這兩種狀態(tài)在linux下統(tǒng)一為 TASK_RUNNING狀態(tài)。S

 (TASK_INTERRUPTIBLE),可中斷的睡眠狀態(tài)。

處于這個狀態(tài)的進程因為等待某某事件的發(fā)生(比如等待socket連接、等待信號量),而被掛起。這些進程的task_struct結(jié)構(gòu)被放入對應事件的等待隊列中。當這些事件發(fā)生時(由外部中斷觸發(fā)、或由其他進程觸發(fā)),對應的等待隊列中的一個或多個進程將被喚醒。

通過ps命令我們會看到,一般情況下,進程列表中的絕大多數(shù)進程都處于TASK_INTERRUPTIBLE狀態(tài)(除非機器的負載很高)。畢竟CPU就這么一兩個,進程動輒幾十上百個,如果不是絕大多數(shù)進程都在睡眠,CPU又怎么響應得過來。D

 (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)。

與TASK_INTERRUPTIBLE狀態(tài)類似,進程處于睡眠狀態(tài),但是此刻進程是不可中斷的。不可中斷,指的并不是CPU不響應外部硬件的中斷,而是指進程不響應異步信號。

絕大多數(shù)情況下,進程處在睡眠狀態(tài)時,總是應該能夠響應異步信號的。否則你將驚奇的發(fā)現(xiàn),kill -9竟然殺不死一個正在睡眠的進程了!于是我們也很好理解,為什么ps命令看到的進程幾乎不會出現(xiàn)TASK_UNINTERRUPTIBLE狀態(tài),而總是TASK_INTERRUPTIBLE狀態(tài)。

而TASK_UNINTERRUPTIBLE狀態(tài)存在的意義就在于,內(nèi)核的某些處理流程是不能被打斷的。如果響應異步信號,程序的執(zhí)行流程中就會被插入一段用于處理異步信號的流程(這個插入的流程可能只存在于內(nèi)核態(tài),也可能延伸到用戶態(tài)),于是原有的流程就被中斷了(參見《linux異步信號handle淺析》)。

在進程對某些硬件進行操作時(比如進程調(diào)用read系統(tǒng)調(diào)用對某個設(shè)備文件進行讀操作,而read系統(tǒng)調(diào)用最終執(zhí)行到對應設(shè)備驅(qū)動的代碼,并與對應的物理設(shè)備進行交互),可能需要使用TASK_UNINTERRUPTIBLE狀態(tài)對進程進行保護,以避免進程與設(shè)備交互的過程被打斷,造成設(shè)備陷入不可控的狀態(tài)。(比如read系統(tǒng)調(diào)用觸發(fā)了一次磁盤到用戶空間的內(nèi)存的DMA,如果DMA進行過程中,進程由于響應信號而退出了,那么DMA正在訪問的內(nèi)存可能就要被釋放了。)這種情況下的TASK_UNINTERRUPTIBLE狀態(tài)總是非常短暫的,通過ps命令基本上不可能捕捉到。

linux系統(tǒng)中也存在容易捕捉的TASK_UNINTERRUPTIBLE狀態(tài)。執(zhí)行vfork系統(tǒng)調(diào)用后,父進程將進入TASK_UNINTERRUPTIBLE狀態(tài),直到子進程調(diào)用exit或exec。

通過下面的代碼就能得到處于TASK_UNINTERRUPTIBLE狀態(tài)的進程:

#include <unistd.h>

void main() {

if (!vfork()) sleep(100);

}

編譯運行,然后ps一下:

kouu@kouu-one:~/test$ ps -ax | grep a\.out

4371 pts/0    D+     0:00 ./a.out

4372 pts/0    S+     0:00 ./a.out

4374 pts/1    S+     0:00 grep a.out

然后我們可以試驗一下TASK_UNINTERRUPTIBLE狀態(tài)的威力。不管kill還是kill -9,這個TASK_UNINTERRUPTIBLE狀態(tài)的父進程依然屹立不倒。T

 (TASK_STOPPED or TASK_TRACED),暫停狀態(tài)或跟蹤狀態(tài)。

向進程發(fā)送一個SIGSTOP信號,它就會因響應該信號而進入TASK_STOPPED狀態(tài)(除非該進程本身處于TASK_UNINTERRUPTIBLE狀態(tài)而不響應信號)。(SIGSTOP與SIGKILL信號一樣,是非常強制的。不允許用戶進程通過signal系列的系統(tǒng)調(diào)用重新設(shè)置對應的信號處理函數(shù)。)

向進程發(fā)送一個SIGCONT信號,可以讓其從TASK_STOPPED狀態(tài)恢復到TASK_RUNNING狀態(tài)。

當進程正在被跟蹤時,它處于TASK_TRACED這個特殊的狀態(tài)?!罢诒桓櫋敝傅氖沁M程暫停下來,等待跟蹤它的進程對它進行操作。比如在gdb中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處于TASK_TRACED狀態(tài)。而在其他時候,被跟蹤的進程還是處于前面提到的那些狀態(tài)。

對于進程本身來說,TASK_STOPPED和TASK_TRACED狀態(tài)很類似,都是表示進程暫停下來。。

而TASK_TRACED狀態(tài)相當于在TASK_STOPPED之上多了一層保護,處于TASK_TRACED狀態(tài)的進程不能響應SIGCONT信號而被喚醒。只能等到調(diào)試進程通過ptrace系統(tǒng)調(diào)用執(zhí)行PTRACE_CONT、PTRACE_DETACH等操作(通過ptrace系統(tǒng)調(diào)用的參數(shù)指定操作),或調(diào)試進程退出,被調(diào)試的進程才能恢復TASK_RUNNING狀態(tài)。Z

 (TASK_DEAD - EXIT_ZOMBIE),退出狀態(tài),進程成為僵尸進程。

進程在退出的過程中,處于TASK_DEAD狀態(tài)。

在這個退出過程中,進程占有的所有資源將被回收,除了task_struct結(jié)構(gòu)(以及少數(shù)資源)以外。于是進程就只剩下task_struct這么個空殼,故稱為僵尸。

之所以保留task_struct,是因為task_struct里面保存了進程的退出碼、以及一些統(tǒng)計信息。而其父進程很可能會關(guān)心這些信息。比如在shell中,$?變量就保存了最后一個退出的前臺進程的退出碼,而這個退出碼往往被作為if語句的判斷條件。

當然,內(nèi)核也可以將這些信息保存在別的地方,而將task_struct結(jié)構(gòu)釋放掉,以節(jié)省一些空間。但是使用task_struct結(jié)構(gòu)更為方便,因為在內(nèi)核中已經(jīng)建立了從pid到task_struct查找關(guān)系,還有進程間的父子關(guān)系。釋放掉task_struct,則需要建立一些新的數(shù)據(jù)結(jié)構(gòu),以便讓父進程找到它的子進程的退出信息。

父進程可以通過wait系列的系統(tǒng)調(diào)用(如wait4、waitid)來等待某個或某些子進程的退出,并獲取它的退出信息。然后wait系列的系統(tǒng)調(diào)用會順便將子進程的尸體(task_struct)也釋放掉。

子進程在退出的過程中,內(nèi)核會給其父進程發(fā)送一個信號,通知父進程來“收尸”。這個信號默認是SIGCHLD,但是在通過clone系統(tǒng)調(diào)用創(chuàng)建子進程時,可以設(shè)置這個信號。

通過下面的代碼能夠制造一個EXIT_ZOMBIE狀態(tài)的進程:

#include <unistd.h>

void main() {

if (fork())

while(1) sleep(100);

}

編譯運行,然后ps一下:

kouu@kouu-one:~/test$ ps -ax | grep a\.out

10410 pts/0    S+     0:00 ./a.out

10411 pts/0    Z+     0:00 [a.out] <defunct>

10413 pts/1    S+     0:00 grep a.out

只要父進程不退出,這個僵尸狀態(tài)的子進程就一直存在。那么如果父進程退出了呢,誰又來給子進程“收尸”?

當進程退出的時候,會將它的所有子進程都托管給別的進程(使之成為別的進程的子進程)。托管給誰呢?可能是退出進程所在進程組的下一個進程(如果存在的話),或者是1號進程。所以每個進程、每時每刻都有父進程存在。除非它是1號進程。

1號進程,pid為1的進程,又稱init進程。

linux系統(tǒng)啟動后,第一個被創(chuàng)建的用戶態(tài)進程就是init進程。它有兩項使命:

1、執(zhí)行系統(tǒng)初始化腳本,創(chuàng)建一系列的進程(它們都是init進程的子孫);

2、在一個死循環(huán)中等待其子進程的退出事件,并調(diào)用waitid系統(tǒng)調(diào)用來完成“收尸”工作;

init進程不會被暫停、也不會被殺死(這是由內(nèi)核來保證的)。它在等待子進程退出的過程中處于TASK_INTERRUPTIBLE狀態(tài),“收尸”過程中則處于TASK_RUNNING狀態(tài)。 X

(TASK_DEAD - EXIT_DEAD),退出狀態(tài),進程即將被銷毀。

而進程在退出過程中也可能不會保留它的task_struct。比如這個進程是多線程程序中被detach過的進程?;蛘吒高M程通過設(shè)置SIGCHLD信號的handler為SIG_IGN,顯式的忽略了SIGCHLD信號。(這是posix的規(guī)定,盡管子進程的退出信號可以被設(shè)置為SIGCHLD以外的其他信號。)

此時,進程將被置于EXIT_DEAD退出狀態(tài),這意味著接下來的代碼立即就會將該進程徹底釋放。所以EXIT_DEAD狀態(tài)是非常短暫的,幾乎不可能通過ps命令捕捉到。

進程的初始狀態(tài)

進程是通過fork系列的系統(tǒng)調(diào)用(fork、clone、vfork)來創(chuàng)建的,內(nèi)核(或內(nèi)核模塊)也可以通過kernel_thread函數(shù)創(chuàng)建內(nèi)核進程。這些創(chuàng)建子進程的函數(shù)本質(zhì)上都完成了相同的功能&mdash;&mdash;將調(diào)用進程復制一份,得到子進程。(可以通過選項參數(shù)來決定各種資源是共享、還是私有。)

那么既然調(diào)用進程處于TASK_RUNNING狀態(tài)(否則,它若不是正在運行,又怎么進行調(diào)用?),則子進程默認也處于TASK_RUNNING狀態(tài)。

另外,在系統(tǒng)調(diào)用調(diào)用clone和內(nèi)核函數(shù)kernel_thread也接受CLONE_STOPPED選項,從而將子進程的初始狀態(tài)置為 TASK_STOPPED。進程狀態(tài)

變遷

進程自創(chuàng)建以后,狀態(tài)可能發(fā)生一系列的變化,直到進程退出。而盡管進程狀態(tài)有好幾種,但是進程狀態(tài)的變遷卻只有兩個方向&mdash;&mdash;從TASK_RUNNING狀態(tài)變?yōu)榉荰ASK_RUNNING狀態(tài)、或者從非TASK_RUNNING狀態(tài)變?yōu)門ASK_RUNNING狀態(tài)。

也就是說,如果給一個TASK_INTERRUPTIBLE狀態(tài)的進程發(fā)送SIGKILL信號,這個進程將先被喚醒(進入TASK_RUNNING狀態(tài)),然后再響應SIGKILL信號而退出(變?yōu)門ASK_DEAD狀態(tài))。并不會從TASK_INTERRUPTIBLE狀態(tài)直接退出。

進程從非TASK_RUNNING狀態(tài)變?yōu)門ASK_RUNNING狀態(tài),是由別的進程(也可能是中斷處理程序)執(zhí)行喚醒操作來實現(xiàn)的。執(zhí)行喚醒的進程設(shè)置被喚醒進程的狀態(tài)為TASK_RUNNING,然后將其task_struct結(jié)構(gòu)加入到某個CPU的可執(zhí)行隊列中。于是被喚醒的進程將有機會被調(diào)度執(zhí)行。

而進程從TASK_RUNNING狀態(tài)變?yōu)榉荰ASK_RUNNING狀態(tài),則有兩種途徑:

1、響應信號而進入TASK_STOPED狀態(tài)、或TASK_DEAD狀態(tài);

2、執(zhí)行系統(tǒng)調(diào)用主動進入TASK_INTERRUPTIBLE狀態(tài)(如nanosleep系統(tǒng)調(diào)用)、或TASK_DEAD狀態(tài)(如exit系統(tǒng)調(diào)用);或由于執(zhí)行系統(tǒng)調(diào)用需要的資源得不到滿足,而進入TASK_INTERRUPTIBLE狀態(tài)或TASK_UNINTERRUPTIBLE狀態(tài)(如select系統(tǒng)調(diào)用)。

顯然,這兩種情況都只能發(fā)生在進程正在CPU上執(zhí)行的情況下。

文章標題:Centos進程狀態(tài)怎么看
標題路徑:http://bm7419.com/article16/dididg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計、網(wǎng)站收錄動態(tài)網(wǎng)站、移動網(wǎng)站建設(shè)、網(wǎng)站改版靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)