1 R 狀態并不直接代表進程在運行,而是該進程在運行隊列中進行排隊,由操作系統在內存維護的隊列
#include <stdio.h>
#include <unistd.h>int main()
{while(1){printf("我在運行嗎\n");sleep(1);}return 0;
}
?查看狀態(ps ajx | grep mytest | grep -v grep)
這里printf本質是向外設打印消息,你在頻繁打印時,外設可能沒就緒,當前進程不在cpu排隊,只在外設中排隊,等設備就緒了,才把數據寫到外設中
- S狀態是阻塞狀態的一種,以休眠的狀態進行阻塞,并沒有一直在cpu運行隊列中,是因為printf而導致等待某中資源
#include <stdio.h>
#include <unistd.h>int main()
{while(1){//printf("我在運行嗎\n");//sleep(1);}return 0;
}
?查看狀態(ps ajx | grep mytest | grep -v grep)
注釋掉就變成R了,代碼中沒有任何訪問資源的代碼,whike循環判斷就是一種計算,當前的代碼就是純計算代碼,在進程調度的生命周期里,只會用cpu資源,只要被調度一定是R狀態
- 本質就是因為cpu太快了,訪問外設,操作系統頻繁的將進程從外設隊列拿到cpu運行隊列,或者cpu運行隊列拿到外設隊列
?2 ?S 休眠狀態,可中斷休眠,本質就是一種阻塞狀態
#include <stdio.h>
#include <unistd.h>int main()
{while(1){int a = 0;scanf("%d", &a);printf("%d", a);}return 0;
}
?查看狀態(ps ajx | grep mytest | grep -v grep)
scanf在等你從鍵盤里輸入,進程沒有被調度,它當前所等的資源沒有就緒,它不會在運行隊列中等,而是在鍵盤中等,等鍵盤有數據了,在把當前進程pcb放到運行隊列里調度,讀取數據;它在等鍵盤資源,這種狀態就叫做阻塞,換句話說就是卡住了,如果不想等了,ctrl+c可以中斷此進程
3 D 休眠狀態,不可中斷休眠
場景:進程想往磁盤中寫入100MB的數據
進程:“磁盤你出來,我現在有數據要交給你,幫我存一下”
磁盤:“你想存多少數據存到哪里?”
進程:“磁盤的角落,我需要把數據保存一下,我一定要寫完數據之后CPU才讓我去跑”
磁盤:“我這個外設太慢了,所以寫100 MB要等等我哦”
這個進程把自己設置成阻塞狀態S,自己就在磁盤的內核數據結構當中進行排隊,cpu就先執行其他人的代碼了,在磁盤進行拷貝的時候,操作系統路過,他作為一個內存的管理者,發現現在內存資源特別緊張
操作系統:“你這個進程在干什么呢?怎么什么都不干在這里等?你沒看系統忙成什么樣子了,內存已經嚴重不足了,我要把你殺掉”(如果你的系統資源嚴重不足,操作系統會干掉一些不怎么正常工作的進程)
干掉的同時磁盤在寫數據,寫的時候發現好像不行了,因為磁盤空間不足了,反正就是因為一些原因,我寫失敗了,這個時候他就去找進程
磁盤:“你這個數據寫入失敗了”
他突然發現人不見了,這個時候就只剩磁盤拿著100 MB的數據在風中流浪,磁盤想著把這個數據丟了,但是萬一這個數據是銀行的轉賬信息呢,保留吧又不知道保存在哪,保存在我的位置,可是對應的進程又不知道我存在什么地方,下次你找我要的時候我忘了怎么辦;反正磁盤就是個辦事的,讓它存哪就存了,但是現在進程沒了,這份數據萬一被搞丟了,到底是這三個人(操作系統、進程、磁盤),其中哪一個人的鍋呢?
問題的根就在于誰叫你操作系統能殺掉進程呢?源碼的設計者突然發現,我們只要保證這個進程不能被殺死不就行了嗎?所以我們就有了一種狀態,休眠狀態D;在linux當中如果一個進程屬于D狀態,該進程無法被殺死,即便是操作系統,也無法殺死D狀態進程,如果這個進程刀槍不入,剛剛的問題就不會產生了,只有當這個D狀態,自己醒來才可以殺掉它,其實還有另一個辦法就是關機重啟,但有時候如果有D狀態,可能都無法正常關機,只要你查到了D狀態,基本上你這個機器已經快宕機了,這個時候只能是拔電源,此時數據丟失的損失就需要你自己承擔了,不過99%的情況不會出現D狀態,哪怕出現一個,當前的系統也已經快要掛了,因為這個D狀態應該一瞬間就完成,主要原因是當前你的磁盤已經非常卡了,壓力很大,來不及給你進行數據寫入,再有兩三個D狀態,再來一些I/O,機器就直接掛掉了,出現宕機;這個D狀態如果做應用開發不用關心,一般是做運維的要關心
?4?T 暫停狀態
- 比如說有一個進程,操作系統不允許你往顯示器上打印消息,但這個用戶就是往顯示器上打印消息,此時為了攔截這個進程的非法行為,操作系統可能把這個進程暫停;休眠和暫停有什么區別,休眠通常是等待某種資源,是真正的阻塞狀態,而是操作系統是在不殺掉這個進程的情況下,停止這個進程的某些行為,比如你想訪問網卡操作系統,發現不能讓你訪問,但這個用戶想要訪問網卡代碼,操作系統就有可能暫停他了,就是你訪問一些你沒有權利訪問的資源操作系統,有時候不想殺掉進程,他就會把你暫停
#include <stdio.h>
#include <unistd.h>int main()
{int count = 0;while(1){printf("我在運行嗎?%d\n", count++);sleep(1);}return 0;
}
?查看狀態(ps ajx | grep mytest | grep -v grep)?
? 暫停進程(kill -19),查看狀態(ps ajx | grep mytest | grep -v grep)
讓進程繼續(kill -18),?查看狀態(ps ajx | grep mytest | grep -v grep)?
現在有兩個現象,ctrl+c終止不了進程,S+狀態變成了S,查進程的時候狀態,如果帶了+號,證明該進程是在前臺運行的,前臺運行可以ctrl+c終止它,但如果沒有+號,意味著這個進程是在后臺運行的,你可以繼續執行你的shell指令,但它在后臺還會繼續執行自己的代碼,可以用9號信號干掉它,(kill -9)
5 追蹤式的暫停
- 關于暫停有一種場景,大家是可以理解的,在調試的時候你不打斷點,你直接運行進程就跑完了,但如果你打了個斷點,你發現當你而運行,他會在斷點處停下來斷點處停下來的本質就是讓進程暫停這就是為什么有時候執行的bug的時候調試某些代碼的時候,我調到一部分想讓他暫停遇到斷點,他會停下來,讓我去查看他的上下文,就是把這個進程暫停了,我們證明一下
makefile(第2行加一個 -g)
1 mytest:test.c2 gcc -o $@ $^ -g 3 .PHONY:clean4 clean:5 rm -f mytest
開始調試(gdb ./mytest)
查看狀態(ps ajx | grep mytest | grep -v grep)?
?查到的t是被追蹤狀態,我啟動的mytest進程,r的時候開始跑,遇到斷點處就停下來了,表示追蹤式的暫停,也是暫停的一種,為什么我們在打斷點他就停下來了,根本原因是gdb遇到斷點處,它會向你的進程發送暫停信號讓你停下來
?6 X && Z
我們為什么創建進程?因為我們要讓進程幫我們辦事,有時候我們會關心結果,有時候不關心結果,當我們想關心結果的時候,我們可以查看進程退出碼,?比如我們的預期結果是100,返回1表示代碼有問題,結果不對
#include <stdio.h>
#include <unistd.h>int main()
{int x = 10;if (x == 100) return 0;else return 1;
}
查看退出碼(echo $?)
X 死亡狀態,發生在一瞬間,幾乎查不到,如果一個進程退出了,立馬X狀態,立馬退出,退出之后進程的所有歷史痕跡,全部被操作系統殺掉,你作為父進程有沒有機會拿到退出結果呢?在Linux中,當進程退出的時候,一般進程不會立即徹底退出,而是要維持一個狀態Z,叫做僵尸狀態,方便后續父進程或者是操作系統讀取該子進程退出的退出結果
比如有一天你去一個地方跑步,跑著跑著,突然看到前面有一個人倒在地板上一動不動,這個時候你撥打了110、120,就在旁邊等著救護人員的到來,警察來之后,第一件事情是封鎖現場,讓法醫先確認這個人的死因是什么,確認這個人是自然死亡的,警察就會通知家屬,讓他們去處理,拉到火葬場等等,剛剛這個場景,人倒在地上沒有被立即銷毀,當警察檢查這個人的狀態時,這個人的狀態就叫做僵尸狀態,為什么要讓他處于僵尸狀態?方便別人來甄別他退出的原因是什么,所以進程要維持短暫的僵尸狀態,關于如何處理,我們下一篇再來談回收,今天重點談狀態
如何讓我們看到僵尸的狀態呢?子進程退出,但是不要回收子進程(目前還沒了解到),換句話說,只要我們寫出來一個父子進程,先讓子進程退出,父進程先不退,子進程一退所處的狀態就是僵尸狀態
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t ret = fork();if (ret == 0){//子進程while(1){printf("我是子進程,pid:%d, ppid:%d\n", getpid(), getppid());sleep(1);}}else{//父進程while(1){printf("我是父進程,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);}}return 0;
}
運行顯示 (./mytest)
?查看狀態(ps ajx | grep mytest | grep -v grep)?
?殺掉子進程(kill -9 [PID]),查看狀態(ps ajx | grep mytest | grep -v grep)
?
雖然我們還沒談到回收,我們可以先來了解,如果不回收會造成什么問題呢?如果我們不釋放操作系統,它就要維持這個進程的狀態、相關的數據結構,也就是pcb,如果不釋放,它曾經申請占用的資源就會一直被占用,創建進程就是申請內存 申請了內存但是長時間不歸還,導致系統能用的資源越來越少,這叫做內存泄露問題,一旦我們回收了進程,就會從Z狀態瞬間變成X狀態,進而操作系統才會真正釋放進程的所有資源,如何回收我們下一個篇章再進行談論