溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

linux進(jìn)程狀態(tài)有哪些

發(fā)布時(shí)間:2023-03-13 10:35:13 來(lái)源:億速云 閱讀:86 作者:iii 欄目:建站服務(wù)器

本篇內(nèi)容主要講解“l(fā)inux進(jìn)程狀態(tài)有哪些”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“l(fā)inux進(jìn)程狀態(tài)有哪些”吧!

linux進(jìn)程有6種狀態(tài):1、R可執(zhí)行狀態(tài),只有該狀態(tài)的進(jìn)程才可能在CPU上運(yùn)行;2、S可中斷的睡眠狀態(tài),處于這個(gè)狀態(tài)的進(jìn)程因?yàn)榈却衬呈录陌l(fā)生,而被掛起;3、D不可中斷的睡眠狀態(tài),進(jìn)程處于睡眠狀態(tài),但是此刻進(jìn)程是不可中斷的;4、T暫停狀態(tài)或跟蹤狀態(tài),向進(jìn)程發(fā)送一個(gè)SIGSTOP信號(hào),它就會(huì)因響應(yīng)該信號(hào)而進(jìn)入T狀態(tài);5、Z僵尸狀態(tài),表示一個(gè)進(jìn)程即將死亡的狀態(tài);6、X死亡狀態(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)教科書(shū)將正在 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)。

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)。

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

與 TASK_INTERRUPTIBLE 狀態(tài)類(lè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),也可能延伸到用戶(hù)態(tà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。

T(TASK_STPPED or TASK_TRACED) 暫停狀態(tài)或跟蹤狀態(tài)

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

向進(jìn)程發(fā)送一個(gè) SIGCONT 信號(hào),可以讓其從 TASK_STOPPED 狀態(tài)恢復(fù)到 TASK_RUNNING 狀態(tài)。

當(dāng)進(jìn)程正在被跟蹤時(shí),它處于 TASK_TRACED 這個(gè)特殊的狀態(tài)?!罢诒桓櫋?指的是進(jìn)程暫停下來(lái),等待跟蹤它的進(jìn)程對(duì)它進(jìn)行操作。比如在 gdb 中對(duì)被跟蹤的進(jìn)程下一個(gè)斷點(diǎn),進(jìn)程在斷點(diǎn)處停下來(lái)的時(shí)候就處于 TASK_TRACED 狀態(tài)。而在其他時(shí)候,被跟蹤的進(jìn)程還是處于前面提到的那些狀態(tài)。

對(duì)于進(jìn)程本身來(lái)說(shuō),TASK_STOPPED 和 TASK_TRACED 狀態(tài)很類(lèi)似,都是表示進(jìn)程暫停下來(lái)。

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

Z(TASK_DEAD - EXIT_ZOMBIE) 僵尸狀態(tài),進(jìn)程成為僵尸進(jìn)程

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

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

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

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

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

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

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

當(dāng)進(jìn)程退出的時(shí)候,會(huì)將它的所有子進(jìn)程都托管給別的進(jìn)程(使之成為別的進(jìn)程的子進(jìn)程)。托管給誰(shuí)呢?可能是退出進(jìn)程所在進(jìn)程組的下一個(gè)進(jìn)程(如果存在的話(huà)),或者是 1 號(hào)進(jìn)程。所以每個(gè)進(jìn)程、每時(shí)每刻都有父進(jìn)程存在。除非它是 1 號(hào)進(jìn)程。

1 號(hào)進(jìn)程,pid 為 1 的進(jìn)程,又稱(chēng) init 進(jìn)程。linux 系統(tǒng)啟動(dòng)后,第一個(gè)被創(chuàng)建的用戶(hù)態(tài)進(jìn)程就是 init 進(jìn)程。它有兩項(xiàng)使命:

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

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

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

X(TASK_DEAD - EXIT_DEAD) 死亡狀態(tài),進(jìn)程即將被銷(xiāo)毀

而進(jìn)程在退出過(guò)程中也可能不會(huì)保留它的 task_struct。比如這個(gè)進(jìn)程是多線程程序中被 detach 過(guò)的進(jìn)程。

或者父進(jìn)程通過(guò)設(shè)置 SIGCHLD 信號(hào)的 handler 為 SIG_IGN,顯式的忽略了 SIGCHLD 信號(hào)。(這是 posix 的規(guī)定,盡管子進(jìn)程的退出信號(hào)可以被設(shè)置為 SIGCHLD 以外的其他信號(hào)。)

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

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

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

那么既然調(diào)用進(jìn)程處于 TASK_RUNNING狀態(tài)(否則,它若不是正在運(yùn)行,又怎么進(jìn)行調(diào)用?),則子進(jìn)程默認(rèn)也處于 TASK_RUNNING 狀態(tài)。另外,在系統(tǒng)調(diào)用調(diào)用 clone 和內(nèi)核函數(shù) kernel_thread 也接受 CLONE_STOPPED 選項(xiàng),從而將子進(jìn)程的初始狀態(tài)置為 TASK_STOPPED。

進(jìn)程狀態(tài)變遷

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

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

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

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

  • 響應(yīng)信號(hào)而進(jìn)入 TASK_STOPED 狀態(tài)、或 TASK_DEAD狀態(tài);

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

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

Linux進(jìn)程狀態(tài)說(shuō)明

狀態(tài)符狀態(tài)全稱(chēng)描 述
RTASK_RUNNING可執(zhí)行狀態(tài)&運(yùn)行狀態(tài)(在 run_queue 隊(duì)列里的狀態(tài))
STASK_INTERRUPTIBLE可中斷的睡眠狀態(tài), 可處理 signal
DTASK_UNINTERRUPTIBLE不可中斷的睡眠狀態(tài), 可處理 signal, 有延遲
TTASK_STOPPED or TASK_TRACED暫停狀態(tài)或跟蹤狀態(tài), 不可處理 signal, 因?yàn)楦緵](méi)有時(shí)間片運(yùn)行代碼
ZTASK_DEAD - EXIT_ZOMBIE退出狀態(tài),進(jìn)程成為僵尸進(jìn)程。不可被 kill, 即不響應(yīng)任務(wù)信號(hào), 無(wú)法用 SIGKILL 殺死

擴(kuò)展知識(shí):什么是等待隊(duì)列,什么是運(yùn)行隊(duì)列,什么是掛起/阻塞,什么叫喚醒進(jìn)程

我們把從運(yùn)行狀態(tài)的task_struct(run_queue),放到等待隊(duì)列中,就叫做掛起等待(阻塞)從等待隊(duì)列,放到運(yùn)行隊(duì)列,被CPU調(diào)度就叫做喚醒進(jìn)程

當(dāng)一個(gè)進(jìn)程在運(yùn)行的過(guò)程中,由于其某些運(yùn)行條件還沒(méi)就緒(比如要網(wǎng)絡(luò)但是網(wǎng)卡了,或者需要等待IO,也就是需要使用外設(shè)了),就會(huì)被放到等待隊(duì)列中,并且task_struct里面的狀態(tài)位也會(huì)被改變?yōu)镾/D。

當(dāng)進(jìn)程處于S/D狀態(tài)的時(shí)候,在一個(gè)等待隊(duì)列里面等著使用外設(shè)(比如網(wǎng)卡,磁盤(pán)顯示器等)

等CPU的隊(duì)列叫做運(yùn)行隊(duì)列,等外設(shè)的設(shè)備叫做等待隊(duì)列

所謂的進(jìn)程,在運(yùn)行的時(shí)候,有可能因?yàn)檫\(yùn)行需要,可以會(huì)在不同的隊(duì)列里

在不同的隊(duì)列里,所處的狀態(tài)是不一樣的

當(dāng)一個(gè)進(jìn)程在R狀態(tài)的時(shí)候,如果需要某種外設(shè),但是外設(shè)在被使用,我就把你的狀態(tài)變成S/D,然后把你的task_struct放到等待隊(duì)列里面去。

到此,相信大家對(duì)“l(fā)inux進(jìn)程狀態(tài)有哪些”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI