日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux进程状态解析

發(fā)布時間:2025/3/18 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux进程状态解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Linux是一個多用戶,多任務的系統(tǒng),可以同時運行多個用戶的多個程序,就必然會產(chǎn)生很多的進程,而每個進程會有 不同的狀態(tài)。


Linux進程狀態(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)度器的任務就是從各個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)。

Linux進程狀態(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又怎么響應得過來。

?


Linux進程狀態(tài):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內(nèi)核異步中斷淺析》)
在進程對某些硬件進行操作時(比如進程調(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)。這種情況下的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(參見《神奇的vfork》)。
通過下面的代碼就能得到處于 TASK_UNINTERRUPTIBLE狀態(tài)的進程:

#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狀態(tài)的威力。不管kill還是kill -9,這個TASK_UNINTERRUPTIBLE狀態(tài)的父進程依然屹立不倒。

Linux進程狀態(tài)解析之T、Z、X

Linux進程狀態(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)。“正在被跟蹤”指的是進程暫停下來,等待跟蹤它的進程對它進行操作。比如在 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)。

Linux進程狀態(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?? 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?

只要父進程不退出,這個僵尸狀態(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)。

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

而進程在退出過程中也可能不會保留它的task_struct。比如這個進程是多線程程序中被detach過的進程(進程?線程?參見《linux 線程淺析》)。或者父進程通過設(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ì)上都完成了相同的功能——將調(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)的變遷卻只有兩個方向——從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í)行的情況下。


轉(zhuǎn)自:http://blog.csdn.net/wanwenweifly4/archive/2011/06/15/6545785.aspx

總結(jié)

以上是生活随笔為你收集整理的Linux进程状态解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。