Linux 进程(一) 进程概念和进程状态(僵尸进程、孤儿进程、守护进程)
- 進(jìn)程的概念
- 進(jìn)程狀態(tài)
- 僵尸進(jìn)程、孤兒進(jìn)程、守護(hù)進(jìn)程
進(jìn)程的概念
程序:一系列有序的指令集合(就是我們寫的代碼)
進(jìn)程:進(jìn)程就是程序的一次執(zhí)行,是系統(tǒng)進(jìn)行資源分配和調(diào)度的獨立單位。
程序是一個沒有生命的實體,只有操作系統(tǒng)執(zhí)行它時,它才能成為一個活動的實體,也就是進(jìn)程。同時,操作系統(tǒng)通過進(jìn)程控制塊(PCB),來對程序進(jìn)行調(diào)度使用
操作系統(tǒng)如何控制和調(diào)度程序
按照馮諾依曼體系結(jié)構(gòu),所有的數(shù)據(jù)想要被CPU進(jìn)行處理,第一步就是要將代碼和數(shù)據(jù)加載到內(nèi)存中。
由于早期CPU的性能不足,無法同時調(diào)度所有文件,所以CPU使用了一種解決方法,也就是CPU分時機(jī)制。
CPU分時機(jī)制:通過極快的速度切換和調(diào)度運(yùn)行所有的程序,造成了同時運(yùn)行的假象。
但是,這里還存在著幾個問題,CPU是如何在內(nèi)存中找到每個程序的?CPU在來回調(diào)度時,如何能夠從上一次運(yùn)行的位置繼續(xù)運(yùn)行?如何能夠保證繼續(xù)處理上一條沒有處理完的數(shù)據(jù)?
所以操作系統(tǒng)為了能夠完成這些操作,設(shè)置了一個用于描述進(jìn)程信息的數(shù)據(jù)結(jié)構(gòu),也就是我們通常所說的PCB。
進(jìn)程控制塊–PCB
操作系統(tǒng)為了能夠使每個程序能夠獨立運(yùn)行,在操作系統(tǒng)中為其配置了一個數(shù)據(jù)結(jié)構(gòu),也就是我們通常所說的PCB(Process Control Block),這個數(shù)據(jù)結(jié)構(gòu)在Linux下是:task_struct
task_struct中的內(nèi)容
標(biāo)示符: 描述本進(jìn)程的唯一標(biāo)示符,用來區(qū)別其他進(jìn)程。
狀態(tài): 任務(wù)狀態(tài),退出代碼,退出信號等。
優(yōu)先級: 相對于其他進(jìn)程的優(yōu)先級。
程序計數(shù)器: 程序中即將被執(zhí)行的下一條指令的地址。
內(nèi)存指針: 包括程序代碼和進(jìn)程相關(guān)數(shù)據(jù)的指針,還有和其他進(jìn)程共享的內(nèi)存塊的指針
上下文數(shù)據(jù): 進(jìn)程執(zhí)行時處理器的寄存器中的數(shù)據(jù)。
I/O狀態(tài)信息:包括顯示的I/O請求,分配給進(jìn)程的I/O設(shè)備和被進(jìn)程使用的文件列表。
記賬信息: 可能包括處理器時間總和,使用的時鐘數(shù)總和,時間限制,記賬號等。 其他信息
PCB是操作系統(tǒng)對一個運(yùn)行中的程序(也就是進(jìn)程)的描述,操作系統(tǒng)通過這個描述來實現(xiàn)對程序的運(yùn)行調(diào)度
操作系統(tǒng)正是通過一個一個的PCB來對運(yùn)行中的程序進(jìn)行調(diào)度使用。
回到前面提出的問題,CPU通過PCB中的內(nèi)存指針來找到程序在內(nèi)存中的地址,通過上下文數(shù)據(jù)來記錄運(yùn)行中程序的各種信息,通過程序計數(shù)器來找到這個程序即將執(zhí)行的下一條指令的地址。
子進(jìn)程
當(dāng)我們在一個已經(jīng)創(chuàng)建的進(jìn)程內(nèi)通過fork創(chuàng)建一個新的進(jìn)程時,這個新的進(jìn)程就是原先進(jìn)程的子進(jìn)程。
在子進(jìn)程創(chuàng)建的時候,它從父進(jìn)程的PCB中復(fù)制了很多數(shù)據(jù),如內(nèi)存指針、上下文數(shù)據(jù)、程序計數(shù)器等,所以它的代碼、數(shù)據(jù)以及運(yùn)行的位置,都與父進(jìn)程一模一樣。
由于代碼段是只讀的,所以兩者的代碼都一樣,不可修改,而兩者雖然虛擬地址相同,但物理地址不同,所以兩者的數(shù)據(jù)都各自獨立。
總結(jié)一下就是:父子進(jìn)程代碼共享,數(shù)據(jù)各自開辟空間。(利用寫時拷貝技術(shù))
在Linux中,我們可以通過fork函數(shù)來創(chuàng)建子進(jìn)程
pid_t fork(void)
我們創(chuàng)建子進(jìn)程,是希望它和父進(jìn)程執(zhí)行不一樣的操作,那么我們該怎么實現(xiàn)呢?
最簡單的方法就是通過fork的返回值來進(jìn)行代碼分流,父進(jìn)程的返回值是子進(jìn)程的pid,而子進(jìn)程的返回值是0,通過對返回值的判斷,即可完成代碼的分流。
但是這種方法的代碼十分冗余,還有一種更加優(yōu)秀的方法------程序替換(后幾篇會寫)
僵尸進(jìn)程、孤兒進(jìn)程、守護(hù)進(jìn)程
在我們學(xué)習(xí)操作系統(tǒng)的時候,里面提到進(jìn)程有三種基本狀態(tài),就緒、阻塞、終止。
但是在linux中,將狀態(tài)細(xì)分到了六種。
- R運(yùn)行狀態(tài)(running): 并不意味著進(jìn)程一定在運(yùn)行中,它表明進(jìn)程要么是在運(yùn)行中要么在運(yùn)行隊列里。
- S睡眠狀態(tài)(sleeping): 意味著進(jìn)程在等待事件完成(這里的睡眠有時候也叫做可中斷睡眠(interruptible sleep))。
- D磁盤休眠狀態(tài)(Disk sleep):有時候也叫不可中斷睡眠狀(uninterruptible sleep),在這個狀態(tài)的進(jìn)程通常會等待IO的結(jié)束。
- T停止?fàn)顟B(tài)(stopped): 可以通過發(fā)送 SIGSTOP 信號給進(jìn)程來停(T)進(jìn)程。這個被暫停的進(jìn)程可以通過發(fā)送 SIGCONT 信號讓進(jìn)程繼續(xù)運(yùn)行。
- X死亡狀態(tài)(dead):這個狀態(tài)只是一個返回狀態(tài),你不會在任務(wù)列表里看到這個狀態(tài)
- Z僵死狀態(tài)(Zombies) :進(jìn)程已經(jīng)退出了但是資源還沒有完全被釋放的一種狀態(tài)。
進(jìn)程的概念
僵尸進(jìn)程
這里的有一種特殊的狀態(tài)值得一提,就是僵死狀態(tài)
當(dāng)子進(jìn)程退出的時候,如果父進(jìn)程沒有讀取到子進(jìn)程的返回值,這時就進(jìn)入了僵死狀態(tài)。
這時就處于一個很尷尬的局面,子進(jìn)程實際上已經(jīng)退出了,但是父進(jìn)程認(rèn)為它還在執(zhí)行,所以并沒有釋放它的資源,所以子進(jìn)程會一直卡在進(jìn)程表中,等待父進(jìn)程讀取退出狀態(tài)代碼。
下面是在Linux下的實驗
此時兩者都處于休眠狀態(tài)
13284是父進(jìn)程, 13285是子進(jìn)程。
這時如果我們使用kill將子進(jìn)程殺死
這時,子進(jìn)程就變?yōu)榱私┦M(jìn)程。
因為它被強(qiáng)制結(jié)束,沒有給父進(jìn)程返回退出的狀態(tài)值,所以資源一直無法釋放,我們也無法再將其殺死
即使是kill -9對其也沒有作用
這時只有兩種解決方法
1. 進(jìn)程等待
2. 退出父進(jìn)程
進(jìn)程等待較為復(fù)雜,后面幾篇會講。
所以我們試試退出父進(jìn)程
父進(jìn)程退出,子進(jìn)程保存退出的狀態(tài)就沒有任何意義了,因此就被釋放了
這時,僵尸進(jìn)程就解決了,但是這并不是一個合理的方式,我們不能通過這種方法來解決問題,所以應(yīng)該避免僵尸進(jìn)程的產(chǎn)生。
從上面可以看出,僵尸進(jìn)程是非常危險的,因為我們無法通過正常途徑將其解決,同時它會一直占用著我們的資源,同時PCB還需要對它的狀態(tài)進(jìn)行維護(hù)。并且一個用戶所能創(chuàng)建的進(jìn)程數(shù)量是有限的,如果一個父進(jìn)程創(chuàng)建了大量的子進(jìn)程而不進(jìn)行回收,當(dāng)達(dá)到上限時,我們就無法創(chuàng)建新的程序。
孤兒進(jìn)程
如果父進(jìn)程先于子進(jìn)程退出,那么沒有父進(jìn)程的子進(jìn)程會怎么樣呢?
會沒有沒有人回收,就像僵尸進(jìn)程一樣一直占用資源?
實驗一下
殺死父進(jìn)程14760
我們會發(fā)現(xiàn),失去了父進(jìn)程后的子進(jìn)程并不是沒有父進(jìn)程,而是會被1號進(jìn)程init統(tǒng)一收養(yǎng),然后由Init進(jìn)程回收
- 父進(jìn)程先退出,子進(jìn)程就稱之為“孤兒進(jìn)程”
- 孤兒進(jìn)程統(tǒng)一被1號init進(jìn)程收養(yǎng),由init進(jìn)程進(jìn)行回收
守護(hù)進(jìn)程(精靈進(jìn)程)
守護(hù)進(jìn)程:一種特殊的孤兒進(jìn)程,父進(jìn)程是一號進(jìn)程,運(yùn)行在后臺,與終端和登陸會話脫離關(guān)系,不受影響。
守護(hù)進(jìn)程通常是一種運(yùn)行在系統(tǒng)后臺的批處理程序,默默的做一些循環(huán)往復(fù)的事情
這些TPGID為-1的都是守護(hù)進(jìn)程
總結(jié)
以上是生活随笔為你收集整理的Linux 进程(一) 进程概念和进程状态(僵尸进程、孤儿进程、守护进程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法 | 计数排序
- 下一篇: Linux 进程(二) 进程地址空间