Linux中行程的六種狀態
目錄
- R運行狀態(running)
- S睡眠狀態(sleeping)
- D磁盤休眠狀態(Disk sleep)
- T停止狀態(stopped)
- Z僵尸狀態(Zombies)
- 僵尸行程是什么
- 為什么要有僵尸行程
- 僵尸行程的危害
- X死亡狀態(dead)
- 孤兒行程
為了弄明白正在運行的行程是什么意思,我們需要知道行程的不同狀態,一個行程可以有幾個狀態(在Linux內核里,行程有時候也叫做任務),


R運行狀態(running)
并不意味著行程一定在運行中,它表明行程要么是在運行中要么在運行佇列,
問題:如果只有一個CPU,可不可以存在多個R狀態的行程,
現場試一下:用fork創建子行程,試一下



可以看到,是可以存在多個運行狀態的,
行程是R狀態,不代表正在運行,代表可被調度,換句話說,行程只有是R狀態才可被調度,其他狀態要先轉為R狀態,才能被OS調度,

S睡眠狀態(sleeping)
意味著行程在等待事件完成(這里的睡眠有時候也叫做可中斷睡眠(interruptible sleep)),
代碼實作一下:


休眠狀態是在等待某種條件就緒,在休眠狀態,可被作業系統殺死,也叫淺度睡眠,
處于這個狀態的行程因為等待某某事件的發生(比如等待socket連接、等待信號量),而被掛起,這些行程的task_struct結構被放入對應事件的等待佇列中,當這些事件發生時(由外部中斷觸發、或由其他行程觸發),對應的等待佇列中的一個或多個行程將被喚醒,

由上圖看到,一般情況下,行程串列中的絕大多數行程都處于S狀態(除非機器的負載很高),畢竟CPU就這么一兩個,行程動輒幾十上百個,如果不是絕大多數行程都在睡眠,CPU又怎么回應得過來,
D磁盤休眠狀態(Disk sleep)
有時候也叫不可中斷睡眠狀態(uninterruptible sleep),在這個狀態的行程通常會等待IO的結束,
可是為什么有了S狀態,又來一個D狀態呢?有什么作用呢?
舉例說明:

T停止狀態(stopped)
可以通過發送 SIGSTOP 信號給行程來停止(T)行程,這個被暫停的行程可以通過發送 SIGCONT 信號讓行程繼續運行,
Z僵尸狀態(Zombies)
代碼實作一下僵尸狀態:
子行程5秒結束,父行程死回圈,不讀取子行程結束資訊,



5秒之后,子行程變為僵尸狀態,
僵尸行程是什么
是一個比較特殊的狀態,當子行程退出并且父行程沒有讀取到子行程退出的回傳代碼時,就會產生僵死(尸)行程,
僵死行程會以終止狀態保持在行程表中,并且會一直在等待父行程讀取退出狀態代碼,所以,只要子行程退出,父行程還在運行,但父行程沒有讀取子行程狀態,子行程進入Z狀態,
為什么要有僵尸行程
因為我們必須得保證一個行程跑完,啟動這個行程的父行程或是作業系統必須得知道這個行程退出時,把我們交代得任務完成得怎么樣了,成功還是失敗了,必須要知道子行程得運行結果,當子行程退出的時候,它的資訊不會立即釋放,會存在PCB中,沒有人讀取,這個狀態不會被釋放掉,這個狀態就是僵尸狀態,
僵尸行程的危害
行程的退出狀態必須被維持下去,因為他要告訴關心它的行程(父行程),你交給我的任務,我辦的怎樣了,可父行程如果一直不讀取,那子行程就一直處于Z狀態?是的!
維護退出狀態本身就是要用資料維護,也屬于行程基本資訊,所以保存在task_struct(PCB)中,換句話說,Z狀態一直不退出,PCB一直都要維護?是的!
那一個父行程創建了很多子行程,就是不回收,是不是就會造成記憶體資源的浪費?是的!
因為資料結構物件本身就要占用記憶體,想想C中定義一個結構體變數(物件),是要在記憶體的某個位置進行開辟空
間!記憶體泄漏?是的!
X死亡狀態(dead)
這個狀態只是一個回傳狀態,你不會在任務串列里看到這個狀態,當父行程讀取子行程的回傳結果時,子行程立刻釋放資源,死亡狀態是非常短暫的,幾乎不可能通過ps命令捕捉到,
孤兒行程
所謂孤兒行程,故名思義,和現實生活中的孤兒有點類似,當一個行程的父行程結束時,但是它自己還沒有結束,那么這個行程將會成為孤兒行程,
孤兒行程會被init行程(1號行程)的行程收養,當然在子行程結束時也會由init行程完成對它的狀態收集作業,因此一般來說,孤兒行程并不會有什么危害.
代碼實作一下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if(id < 0){
perror("fork");
return 1;
}
else if(id == 0){//child
printf("I am child, pid : %d\n", getpid());
sleep(10);
}else{//parent
printf("I am parent, pid: %d\n", getpid());
sleep(3);
exit(0);
}
return 0;
}

由圖可以看出,當父行程結束時,父行程由4416變為1號行程,子行程4417被1號行程領養,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/300744.html
標籤:其他
上一篇:資料結構:佇列
