Linux進程狀態(ps stat)之R、S、D、T、Z、X__Linux

來源:互聯網
上載者:User
轉載自:http://blog.csdn.net/brucexu1978/article/details/7721313
Linux進程狀態(ps stat)之R、S、D、T、Z、X
2012 年 03 月 11 日 Posted by  Jian
ps 進程狀態:PROCESS STATE CODES PROCESS STATE CODES
Here are the different values that the s, stat and state output specifiers
(header "STAT" or "S") will display to describe the state of a process.
D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct ("zombie") process, terminated but not reaped by its parent.

For BSD formats and when the stat keyword is used, additional characters may
be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group

1、ps 的參數說明

ps 提供了很多的選項參數,常用的有以下幾個:

l 長格式輸出;

u 按使用者名稱和啟動時間的順序來顯示進程;

j 用任務格式來顯示進程;

f 用樹形格式來顯示進程;

a 顯示所有使用者的所有進程(包括其它使用者);

x 顯示不控制終端的進程;

r 顯示運行中的進程;

ww 避免詳細參數被截斷;

我們常用的選項是組合是 aux 或 lax,還有參數 f 的應用。

2、ps aux 或 lax 輸出的解釋

USER 進程的屬主;

PID 進程的ID;

PPID 父進程;

%CPU 進程佔用的CPU百分比;

%MEM 佔用記憶體的百分比;

NI 進程的NICE值,數值大,表示較少佔用CPU時間;

VSZ 進程虛擬大小;

RSS 駐留中頁的數量;

TTY 終端ID

STAT 進程狀態(有以下幾種)

D 無法中斷的休眠狀態(通常 IO 的進程);

R 正在運行可中在隊列中可過行的;

S 處於休眠狀態;

T 停止或被追蹤;

W 進入記憶體交換(從核心2.6開始無效);

X 死掉的進程(從來沒見過);

Z 殭屍進程;

< 優先順序高的進程

N 優先順序較低的進程

L 有些頁被鎖進記憶體;

s 進程的領導者(在它之下有子進程);

l 多進程的(使用 CLONE_THREAD, 類似 NPTL pthreads);

+ 位於背景進程組;

WCHAN 正在等待的進程資源;

START 啟動進程的時間;

TIME 進程消耗CPU的時間;

COMMAND 命令的名稱和參數;

3 使用ps格式輸出來查看進程狀態:
ps -eo user,stat..,cmd

user 使用者名稱
uid 使用者號
pid 進程號
ppid 父進程號
size 記憶體大小, Kbytes位元組.
vsize 總虛擬記憶體大小, bytes位元組(包含code+data+stack)
share 總共用頁數
nice 進程優先順序(預設為0, 最大為-20)
priority(pri) 核心調度優先順序
pmem 進程分享的實體記憶體數的百分比
trs 程式執行代碼駐留大小
rss 進程使用的總實體記憶體數, Kbytes位元組
time 進程執行起到現在總的CPU暫用時間
stat 進程狀態
cmd(args) 執行命令的簡單格式

例子:
查看當前系統進程的uid,pid,stat,pri, 以uid號排序.
ps -eo pid,stat,pri,uid –sort uid

查看當前系統進程的user,pid,stat,rss,args, 以rss排序.
ps -eo user,pid,stat,rss,args –sort rss

Linux是一個多使用者,多任務的系統,可以同時運行多個使用者的多個程式,就必然會產生很多的進程,而每個進程會有不同的狀態。

Linux進程狀態:R (TASK_RUNNING),可執行狀態。

只有在該狀態的進程才可能在CPU上運行。而同一時刻可能有多個進程處於可執行狀態,這些進程的task_struct結構(進程式控制制塊)被放入對應CPU的可執行隊列中(一個進程最多隻能出現在一個CPU的可執行隊列中)。進程調度器的任務就是從各個CPU的可執行隊列中分別選擇一個進程在該CPU上運行。

很多作業系統教科書將正在CPU上執行的進程定義為RUNNING狀態、而將可執行但是尚未被調度執行的進程定義為READY狀態,這兩種狀態在linux下統一為 TASK_RUNNING狀態。

Linux進程狀態:S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態。

處於這個狀態的進程因為等待某某事件的發生(比如等待socket串連、等待訊號量),而被掛起。這些進程的task_struct結構被放入對應事件的等待隊列中。當這些事件發生時(由外部中斷觸發、或由其他進程觸發),對應的等待隊列中的一個或多個進程將被喚醒。

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

Linux進程狀態:D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態。

與TASK_INTERRUPTIBLE狀態類似,進程處於睡眠狀態,但是此刻進程是不可中斷的。不可中斷,指的並不是CPU不響應外部硬體的中斷,而是指進程不響應非同步訊號。
絕大多數情況下,進程處在睡眠狀態時,總是應該能夠響應非同步訊號的。否則你將驚奇的發現,kill -9竟然殺不死一個正在睡眠的進程了。於是我們也很好理解,為什麼ps命令看到的進程幾乎不會出現TASK_UNINTERRUPTIBLE狀態,而總是TASK_INTERRUPTIBLE狀態。

而TASK_UNINTERRUPTIBLE狀態存在的意義就在於,核心的某些處理流程是不能被打斷的。如果響應非同步訊號,程式的執行流程中就會被插入一段用於處理非同步訊號的流程(這個插入的流程可能只存在於核心態,也可能延伸到使用者態),於是原有的流程就被中斷了。(參見《linux核心非同步中斷淺析》)
在進程對某些硬體進行操作時(比如進程調用read系統調用對某個裝置檔案進行讀操作,而read系統調用最終執行到對應裝置驅動的代碼,並與對應的物理裝置進行互動),可能需要使用TASK_UNINTERRUPTIBLE狀態對進程進行保護,以避免進程與裝置互動的過程被打斷,造成裝置陷入不可控的狀態。這種情況下的TASK_UNINTERRUPTIBLE狀態總是非常短暫的,通過ps命令基本上不可能捕捉到。

linux系統中也存在容易捕捉的TASK_UNINTERRUPTIBLE狀態。執行vfork系統調用後,父進程將進入TASK_UNINTERRUPTIBLE狀態,直到子進程調用exit或exec(參見《神奇的vfork》)。
通過下面的代碼就能得到處於TASK_UNINTERRUPTIBLE狀態的進程: #include 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狀態的威力。不管kill還是kill -9,這個TASK_UNINTERRUPTIBLE狀態的父進程依然屹立不倒。

Linux進程狀態:T (TASK_STOPPED or TASK_TRACED),暫停狀態或跟蹤狀態。

向進程發送一個SIGSTOP訊號,它就會因響應該訊號而進入TASK_STOPPED狀態(除非該進程本身處於TASK_UNINTERRUPTIBLE狀態而不響應訊號)。(SIGSTOP與SIGKILL訊號一樣,是非常強制的。不允許使用者進程通過signal系列的系統調用重新設定對應的訊號處理函數。)
向進程發送一個SIGCONT訊號,可以讓其從TASK_STOPPED狀態恢複到TASK_RUNNING狀態。

當進程正在被跟蹤時,它處於TASK_TRACED這個特殊的狀態。“正在被跟蹤”指的是進程暫停下來,等待跟蹤它的進程對它進行操作。比如在gdb中對被跟蹤的進程下一個斷點,進程在斷點處停下來的時候就處於TASK_TRACED狀態。而在其他時候,被跟蹤的進程還是處於前面提到的那些狀態。

對於進程本身來說,TASK_STOPPED和TASK_TRACED狀態很類似,都是表示進程暫停下來。
而TASK_TRACED狀態相當於在TASK_STOPPED之上多了一層保護,處於TASK_TRACED狀態的進程不能響應SIGCONT訊號而被喚醒。只能等到調試進程通過ptrace系統調用執行PTRACE_CONT、PTRACE_DETACH等操作(通過ptrace系統調用的參數指定操作),或調試進程退出,被調試的進程才能恢複TASK_RUNNING狀態。

Linux進程狀態:Z (TASK_DEAD – EXIT_ZOMBIE),退出狀態,進程成為殭屍進程。

進程在退出的過程中,處於TASK_DEAD狀態。

在這個退出過程中,進程佔有的所有資源將被回收,除了task_struct結構(以及少數資源)以外。於是進程就只剩下task_struct這麼個空殼,故稱為殭屍。
之所以保留task_struct,是因為task_struct裡面儲存了進程的退出碼、以及一些統計資訊。而其父進程很可能會關心這些資訊。比如在shell中,$?變數就儲存了最後一個退出的前台進程的退出碼,而這個退出碼往往被作為if語句的判斷條件。
當然,核心也可以將這些資訊儲存在別的地方,而將task_struct結構釋放掉,以節省一些空間。但是使用task_struct結構更為方便,因為在核心中已經建立了從pid到task_struct尋找關係,還有進程間的父子關係。釋放掉task_struct,則需要建立一些新的資料結構,以便讓父進程找到它的子進程的退出資訊。

父進程可以通過wait系列的系統調用(如wait4、waitid)來等待某個或某些子進程的退出,並擷取它的退出資訊。然後wait系列的系統調用會順便將子進程的屍體(task_struct)也釋放掉。
子進程在退出的過程中,核心會給其父進程發送一個訊號,通知父進程來“收屍”。這個訊號預設是SIGCHLD,但是在通過clone系統調用建立子進程時,可以設定這個訊號。

通過下面的代碼能夠製造一個EXIT_ZOMBIE狀態的進程: #include 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] 10413 pts/1    S+     0:00 grep a.out

只要父進程不退出,這個殭屍狀態的子進程就一直存在。那麼如果父進程退出了呢,誰又來給子進程“收屍”。
當進程退出的時候,會將它的所有子進程都託管給別的進程(使之成為別的進程的子進程)。託管給誰呢。可能是退出進程所在進程組的下一個進程(如果存在的話),或者是1號進程。所以每個進程、每時每刻都有父進程存在。除非它是1號進程。

1號進程,pid為1的進程,又稱init進程。
linux系統啟動後,第一個被建立的使用者態進程就是init進程。它有兩項使命:
1、執行系統初始化指令碼,建立一系列的進程(它們都是init進程的子孫);
2、在一個死迴圈中等待其子進程的退出事件,並調用waitid系統調用來完成“收屍”工作;
init進程不會被暫停、也不會被殺死(這是由核心來保證的)。它在等待子進程退出的過程中處於TASK_INTERRUPTIBLE狀態,“收屍”過程中則處於TASK_RUNNING狀態。

Linux進程狀態:X (TASK_DEAD – EXIT_DEAD),退出狀態,進程即將被銷毀。

而進程在退出過程中也可能不會保留它的task_struct。比如這個進程是多線程程式中被detach過的進程(進程。線程。參見《linux線程淺析》)。或者父進程通過設定SIGCHLD訊號的handler為SIG_IGN,顯式的忽略了SIGCHLD訊號。(這是posix的規定,儘管子進程的退出訊號可以被設定為SIGCHLD以外的其他訊號。)
此時,進程將被置於EXIT_DEAD退出狀態,這意味著接下來的代碼立即就會將該進程徹底釋放。所以EXIT_DEAD狀態是非常短暫的,幾乎不可能通過ps命令捕捉到。

進程的初始狀態

進程是通過fork系列的系統調用(fork、clone、vfork)來建立的,核心(或核心模組)也可以通過kernel_thread函數建立核心進程。這些建立子進程的函數本質上都完成了相同的功能——將調用進程複製一份,得到子進程。(可以通過選項參數來決定各種資源是共用、還是私人。)
那麼既然調用進程處於TASK_RUNNING狀態(否則,它若不是正在運行,又怎麼進行調用。),則子進程預設也處於TASK_RUNNING狀態。
另外,在系統調用調用clone和核心功能kernel_thread也接受CLONE_STOPPED選項,從而將子進程的初始狀態置為 TASK_STOPPED。

進程狀態變遷

進程自建立以後,狀態可能發生一系列的變化,直到進程退出。而儘管進程狀態有好幾種,但是進程狀態的變遷卻只有兩個方向——從TASK_RUNNING狀態變為非TASK_RUNNING狀態、或者從非TASK_RUNNING狀態變為TASK_RUNNING狀態。
也就是說,如果給一個TASK_INTERRUPTIBLE狀態的進程發送SIGKILL訊號,這個進程將先被喚醒(進入TASK_RUNNING狀態),然後再響應SIGKILL訊號而退出(變為TASK_DEAD狀態)。並不會從TASK_INTERRUPTIBLE狀態直接退出。

進程從非TASK_RUNNING狀態變為TASK_RUNNING狀態,是由別的進程(也可能是中斷處理常式)執行喚醒操作來實現的。執行喚醒的進程設定被喚醒進程的狀態為TASK_RUNNING,然後將其task_struct結構加入到某個CPU的可執行隊列中。於是被喚醒的進程將有機會被調度執行。

而進程從TASK_RUNNING狀態變為非TASK_RUNNING狀態,則有兩種途徑:
1、響應訊號而進入TASK_STOPED狀態、或TASK_DEAD狀態;
2、執行系統調用主動進入TASK_INTERRUPTIBLE狀態(如nanosleep系統調用)、或TASK_DEAD狀態(如exit系統調用);或由於執行系統調用需要的資源得不到滿足,而進入TASK_INTERRUPTIBLE狀態或TASK_UNINTERRUPTIBLE狀態(如select系統調用)。
顯然,這兩種情況都只能發生在進程正在CPU上執行的情況下。

核心模組代碼:
—————-killd.c—————-
#include #include #include //for_each_process
MODULE_LICENSE(“BSD”);
static int pid = -1;
module_param(pid, int, S_IRUGO);
static int killd_init(void)
{
struct task_struct * p;
printk(KERN_ALERT “killd: force D status process to death\n”);
printk(KERN_ALERT “killd: pid=%d\n”, pid);
//read_lock(&tasklist_lock);
for_each_process(p){
if(p->pid == pid){
printk(“killd: found\n”);
set_task_state(p, TASK_STOPPED);
printk(KERN_ALERT “killd: aha, dead already\n”);
return 0;
}
}
printk(“not found”);
//read_unlock(&tasklist_lock);
return 0;
}
static void killd_exit(void)
{
printk(KERN_ALERT “killd: bye\n”);
}
module_init(killd_init);
module_exit(killd_exit);
—–Makefile————
obj-m := killd.o
編譯模組
make -C yourkerneltree M=`pwd` modules
插入模組的時候提供D狀態的進程號,就可以將其轉換為stopped狀態,使用普通kill就可以殺死。
./insmod ./killd.ko pid=1234

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.