Linux進(jìn)程狀態(tài)解析之R、S、D
Linux是一個(gè)多用戶,多任務(wù)的系統(tǒng),可以同時(shí)運(yùn)行多個(gè)用戶的多個(gè)程序,就必然會(huì)產(chǎn)生很多的進(jìn)程,而每個(gè)進(jìn)程會(huì)有不同的狀態(tài)。
Linux進(jìn)程狀態(tài):R (TASK_RUNNING),可執(zhí)行狀態(tài)。
只有在該狀態(tài)的進(jìn)程才可能在CPU上運(yùn)行。而同一時(shí)刻可能有多個(gè)進(jìn)程處于可執(zhí)行狀態(tài),這些進(jìn)程的task_struct結(jié)構(gòu)(進(jìn)程控制塊)被放入對(duì)應(yīng)CPU的可執(zhí)行隊(duì)列中(一個(gè)進(jìn)程最多只能出現(xiàn)在一個(gè)CPU的可執(zhí)行隊(duì)列中)。進(jìn)程調(diào)度器的任務(wù)就是從各個(gè)CPU的可執(zhí)行隊(duì)列中分別選擇一個(gè)進(jìn)程在該CPU上運(yùn)行。
很多操作系統(tǒng)教科書將正在CPU上執(zhí)行的進(jìn)程定義為RUNNING狀態(tài)、而將可執(zhí)行但是尚未被調(diào)度執(zhí)行的進(jìn)程定義為READY狀態(tài),這兩種狀態(tài)在linux下統(tǒng)一為 TASK_RUNNING狀態(tài)。
Linux進(jìn)程狀態(tài):S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態(tài)。
處于這個(gè)狀態(tài)的進(jìn)程因?yàn)榈却衬呈录陌l(fā)生(比如等待socket連接、等待信號(hào)量),而被掛起。這些進(jìn)程的task_struct結(jié)構(gòu)被放入對(duì)應(yīng)事件的等待隊(duì)列中。當(dāng)這些事件發(fā)生時(shí)(由外部中斷觸發(fā)、或由其他進(jìn)程觸發(fā)),對(duì)應(yīng)的等待隊(duì)列中的一個(gè)或多個(gè)進(jìn)程將被喚醒。
通過(guò)ps命令我們會(huì)看到,一般情況下,進(jìn)程列表中的絕大多數(shù)進(jìn)程都處于TASK_INTERRUPTIBLE狀態(tài)(除非機(jī)器的負(fù)載很高)。畢竟CPU就這么一兩個(gè),進(jìn)程動(dòng)輒幾十上百個(gè),如果不是絕大多數(shù)進(jìn)程都在睡眠,CPU又怎么響應(yīng)得過(guò)來(lái)。
Linux進(jìn)程狀態(tài):D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)。
與TASK_INTERRUPTIBLE狀態(tài)類似,進(jìn)程處于睡眠狀態(tài),但是此刻進(jìn)程是不可中斷的。不可中斷,指的并不是CPU不響應(yīng)外部硬件的中斷,而是指進(jìn)程不響應(yīng)異步信號(hào)。
絕大多數(shù)情況下,進(jìn)程處在睡眠狀態(tài)時(shí),總是應(yīng)該能夠響應(yīng)異步信號(hào)的。否則你將驚奇的發(fā)現(xiàn),kill -9竟然殺不死一個(gè)正在睡眠的進(jìn)程了!于是我們也很好理解,為什么ps命令看到的進(jìn)程幾乎不會(huì)出現(xiàn)TASK_UNINTERRUPTIBLE狀態(tài),而總是TASK_INTERRUPTIBLE狀態(tài)。
而TASK_UNINTERRUPTIBLE狀態(tài)存在的意義就在于,內(nèi)核的某些處理流程是不能被打斷的。如果響應(yīng)異步信號(hào),程序的執(zhí)行流程中就會(huì)被插入一段用于處理異步信號(hào)的流程(這個(gè)插入的流程可能只存在于內(nèi)核態(tài),也可能延伸到用戶態(tài)),于是原有的流程就被中斷了。(參見(jiàn)《linux內(nèi)核異步中斷淺析》)
在進(jìn)程對(duì)某些硬件進(jìn)行操作時(shí)(比如進(jìn)程調(diào)用read系統(tǒng)調(diào)用對(duì)某個(gè)設(shè)備文件進(jìn)行讀操作,而read系統(tǒng)調(diào)用最終執(zhí)行到對(duì)應(yīng)設(shè)備驅(qū)動(dòng)的代碼,并與對(duì)應(yīng)的物理設(shè)備進(jìn)行交互),可能需要使用TASK_UNINTERRUPTIBLE狀態(tài)對(duì)進(jìn)程進(jìn)行保護(hù),以避免進(jìn)程與設(shè)備交互的過(guò)程被打斷,造成設(shè)備陷入不可控的狀態(tài)。這種情況下的TASK_UNINTERRUPTIBLE狀態(tài)總是非常短暫的,通過(guò)ps命令基本上不可能捕捉到。
linux系統(tǒng)中也存在容易捕捉的TASK_UNINTERRUPTIBLE狀態(tài)。執(zhí)行vfork系統(tǒng)調(diào)用后,父進(jìn)程將進(jìn)入TASK_UNINTERRUPTIBLE狀態(tài),直到子進(jìn)程調(diào)用exit或exec(參見(jiàn)《神奇的vfork》)。
通過(guò)下面的代碼就能得到處于TASK_UNINTERRUPTIBLE狀態(tài)的進(jìn)程:
- #include
- void main() {
- if (!vfork()) sleep(100);
- }
編譯運(yùn)行,然后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
然后我們可以試驗(yàn)一下TASK_UNINTERRUPTIBLE狀態(tài)的威力。不管kill還是kill -9,這個(gè)TASK_UNINTERRUPTIBLE狀態(tài)的父進(jìn)程依然屹立不倒。
【編輯推薦】