Linux操作系統從入門到實戰(十九)進程狀態
- 前言
- 一、什么是進程狀態
- 二、狀態本質
- 三、最核心的3種狀態
- 1. 就緒狀態
- 2. 運行狀態
- 3. 阻塞狀態
- 四、狀態變化的核心
- 1/兩種資源如何影響狀態?
- 五、操作系統怎么管理這些狀態?
- 六、Linux里結構體與狀態
- 七、回顧:“父進程”和“子進程”
- 八、僵尸進程
- 1. 什么是僵尸進程?
- 2. 僵尸進程是怎么產生的?
- 3. 看個例子:30秒的僵尸進程
- 4. 僵尸進程的危害
- 九、孤兒進程
- 1. 什么是孤兒進程?
- 2. 孤兒進程會變成僵尸嗎?
- 3. 看個例子
前言
- 上一篇博客里我們講解了Linux里面怎么查看進程
- 這篇博客我們開始講解進程狀態與僵尸和孤兒進程
我的個人主頁,歡迎來閱讀我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知識文章專欄
歡迎來閱讀指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482
一、什么是進程狀態
- 前面我們講過可以把“進程”理解成“正在運行的程序”(比如你打開的微信、瀏覽器,本質上都是一個或多個進程)。
而==“進程狀態”==,就是這個“正在運行的程序”當前的“處境”——它現在是在干活?還是在等東西?還是準備好了就等機會干活?
簡單說:進程狀態就是用來描述“這個進程現在能干啥、接下來要干啥”的標記。
二、狀態本質
聽起來好像很復雜,但其實在電腦(操作系統)內部,** 進程狀態就是一個簡單的數字 **。
比如:操作系統可能用“0”表示“準備好了”,用“1”表示“正在干活”,用“2”表示“在等東西”。不同的操作系統數字可能不一樣,但核心邏輯都差不多——用數字標記“進程當前的狀態”。
三、最核心的3種狀態
所有操作系統(不管是Windows、Linux還是手機系統),管理進程狀態的邏輯都差不多,最核心的就3種狀態:** 就緒狀態、運行狀態、阻塞狀態 **。
我們可以用一個生活例子理解:把“進程”比作“去食堂打飯的同學”,“CPU(電腦的核心)”比作“打飯窗口”。
1. 就緒狀態
比如你到了食堂,發現窗口正在有人打飯,你就站在隊伍里等著——這時候你就是“就緒狀態”。
對應到進程:
- 進程已經把所有“準備工作”做好了(比如需要的內存、數據都齊了);
- 就差“CPU(打飯窗口)”有空了,一旦CPU輪到它,它就能立刻開始干活。
2. 運行狀態
當窗口空出來,輪到你打飯了——這時候你就是“運行狀態”。
對應到進程:
- 進程正在被CPU“處理”,比如正在執行代碼(算數學題、處理文字等);
- 只要CPU沒“輪到下一個”,它就一直處于這個狀態。
3. 阻塞狀態
假設你打飯時發現沒勺子,得先去旁邊取勺子,這時候你就暫時離開隊伍,等拿到勺子再回來排隊——這時候你就是“阻塞狀態”。
對應到進程:
- 進程暫時沒法用CPU干活,因為它在等“外設資源”(比如等鍵盤輸入、等硬盤讀寫數據、等網絡傳輸完成);
- 必須等外設資源準備好了(比如你拿到勺子),它才會重新回到“就緒狀態”(回到隊伍),再等CPU來處理。
四、狀態變化的核心
為什么進程會在這3種狀態之間切換?本質是因為進程在“搶資源”,而資源只有兩種:
- ** CPU資源 **:就是“打飯窗口”,誰搶到誰就能“運行”;
- ** 外設資源 **:就是“勺子、餐盤”這類,比如鍵盤、鼠標、硬盤、網絡等。
1/兩種資源如何影響狀態?
- 如果你是“計算密集型”任務(比如跑復雜的數學公式、處理大數據):主要搶CPU資源,大部分時間要么在“運行”(用CPU),要么在“就緒”(等CPU)。
- 如果你是“IO密集型”任務(比如用微信發消息、用瀏覽器下載文件):主要搶外設資源(發消息要等網絡,下載要等硬盤),大部分時間可能在“阻塞”(等外設),偶爾回到“就緒”和“運行”。
五、操作系統怎么管理這些狀態?
操作系統會給每個CPU建一個“調度隊列”(就像食堂的隊伍):
- 所有“就緒狀態”的進程,都會排在這個隊列里,等著CPU來“叫號”;
- 一旦CPU“叫到”某個進程,這個進程就從“就緒”變成“運行”;
- 如果運行中的進程需要等外設(比如等你輸入文字),就會離開隊列,進入“阻塞”;等外設準備好了,再重新回到“就緒隊列”排隊。
六、Linux里結構體與狀態
最后簡單提一下Linux系統里的實現。
在Linux中,每個進程的信息(包括狀態、占用的資源、位置等)都存在一個叫“PCB(進程控制塊)”的結構體里(可以理解成“進程的身份證+檔案”)。
- 結構體就像一個“抽屜”,里面有很多“小格子”(成員),每個格子存不同的信息(比如狀態、內存地址等)。
- 如果你知道某個“小格子”(比如狀態這個數字)的地址,就能反推出整個“抽屜”(結構體)的起始地址(就像知道抽屜里某本書的位置,就能找到整個抽屜在哪)。
- 想訪問結構體里的信息(比如狀態),直接用“結構體變量.成員名”就行(比如“進程檔案.狀態”)。
七、回顧:“父進程”和“子進程”
就像現實中父母會生孩子,一個進程(比如你打開的瀏覽器)也能“創建”新的進程(比如瀏覽器新開的標簽頁進程)。我們把“創建者”叫** 父進程 ,“被創建的”叫 子進程 **。
它們的關系就像:父進程“管”子進程,子進程干完活后,要告訴父進程“結果咋樣”(比如“任務完成”或“出錯了”)。
八、僵尸進程
1. 什么是僵尸進程?
簡單說:子進程已經退出(“死了”),但父進程一直沒“問”它“死之前干得咋樣”,這時候子進程就變成了僵尸進程。
用生活例子類比:
你(子進程)幫爸媽(父進程)做一件事,做完后你告訴爸媽“我完事了”,但爸媽一直在忙別的,沒理你。這時候你雖然“任務結束”了,但還得等著爸媽回應,就像“僵尸”一樣,沒徹底“消失”。
2. 僵尸進程是怎么產生的?
子進程退出時,會留下一個“退出狀態碼”(比如“0”表示成功,“1”表示失敗),這個碼是給父進程看的。
- 如果父進程及時用
wait()
(可以理解成“詢問結果”)讀取了這個碼,子進程就會徹底消失; - 但如果父進程沒讀(比如父進程在睡覺、忙別的),子進程就會保持“僵尸狀態(Z狀態)”,留在系統的“進程表”里,等著父進程來“處理”。
3. 看個例子:30秒的僵尸進程
有一段代碼(不用看懂細節,知道邏輯就行):
- 父進程創建子進程后,自己睡30秒(期間不處理子進程);
- 子進程創建后,只睡5秒就退出了。
這時候:
- 子進程5秒后“死了”,留下退出狀態碼;
- 父進程還在睡覺(30秒),沒讀這個碼;
- 所以子進程在這25秒(30-5)里,就成了僵尸進程,狀態是Z。
4. 僵尸進程的危害
僵尸進程雖然“死了”,但它的“檔案”(PCB,之前講過的“進程身份證+信息表”)還在系統里存著——因為要保留“退出狀態碼”等信息,等著父進程來取。
問題來了:
- 一個僵尸進程的PCB占一點內存,看起來不多;
- 但如果父進程創建了很多子進程,還都不管(不讀狀態碼),就會有一堆僵尸進程的PCB占內存,最后導致“內存泄漏”(內存被白白浪費,用不了)。
九、孤兒進程
1. 什么是孤兒進程?
和僵尸進程相反:** 父進程先退出(“死了”),但子進程還在運行,這時候子進程就成了孤兒進程 **。
生活例子類比:
爸媽(父進程)提前“離開”了,你(子進程)還沒長大(還在運行),這時候你就成了“孤兒”。
2. 孤兒進程會變成僵尸嗎?
不會。因為操作系統有“兜底機制”:
當父進程先死,子進程會被系統的“1號進程”(可以理解成“系統大管家”,比如Linux里的init
進程)“領養”。
- 1號進程會負責“接管”這個孤兒進程,等它退出后,及時讀取它的退出狀態碼;
- 所以孤兒進程退出后,不會變成僵尸,會被1號進程徹底“清理”掉。
3. 看個例子
一段代碼邏輯:
- 父進程創建子進程后,自己只睡3秒就退出了;
- 子進程會睡10秒才退出(比父進程活得久)。
這時候:
- 父進程3秒后“死了”,子進程還在運行,成了孤兒;
- 系統的1號進程會“領養”這個孤兒;
- 10秒后子進程退出,1號進程會及時讀取它的狀態碼,子進程正常消失,不會變僵尸。
類型 | 產生原因 | 結果/危害 | 系統處理方式 |
---|---|---|---|
僵尸進程 | 子進程先死,父進程沒讀它的退出碼 | 留在進程表,占內存,可能導致內存泄漏 | 父進程用wait() 讀取狀態碼即可清除 |
孤兒進程 | 父進程先死,子進程還在運行 | 不會變僵尸,會被1號進程領養并正常回收 | 1號進程接管,負責后續清理 |
以上就是這篇博客的全部內容,下一篇我們將繼續探索Linux的更多精彩內容。
我的個人主頁
歡迎來閱讀我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知識文章專欄
歡迎來閱讀指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482
非常感謝您的閱讀,喜歡的話記得三連哦 |