> 作者簡介:?舊言~,目前大二,現(xiàn)在學(xué)習(xí)Java,c,c++,Python等
> 座右銘:松樹千年終是朽,槿花一日自為榮。> 目標(biāo):了解馮諾依曼體系結(jié)構(gòu)與操作系統(tǒng),掌握Linux的進(jìn)程
> 毒雞湯:一花凋零荒蕪不了整個(gè)春天,一次挫折也荒廢不了整個(gè)人生。
> 望小伙伴們點(diǎn)贊??收藏?加關(guān)注喲?????
??前言
????????本篇博客基于學(xué)習(xí)完馮諾依曼體系結(jié)構(gòu)與操作系統(tǒng)及其進(jìn)程,進(jìn)一步深度理解進(jìn)程,學(xué)習(xí)完本篇對(duì)進(jìn)程的理解會(huì)更上一層樓,想必大家已經(jīng)按耐不住接收新的知識(shí),那咱們?cè)挷欢嗾f進(jìn)入今天的主題--->【Linux】進(jìn)程狀態(tài)、進(jìn)程優(yōu)先級(jí)和進(jìn)程切換????。
?主體
我們從以下學(xué)習(xí)【Linux】進(jìn)程狀態(tài)、進(jìn)程優(yōu)先級(jí)和進(jìn)程切換????。
??操作系統(tǒng)進(jìn)程
????????由于Linux是一個(gè)多用戶,多任務(wù)的系統(tǒng),可以同時(shí)運(yùn)行多個(gè)用戶的多個(gè)程序,就必然會(huì)產(chǎn)生很多的進(jìn)程,而每個(gè)進(jìn)程會(huì)有不同的狀態(tài)。
????????進(jìn)程狀態(tài):一個(gè)程序被加載到內(nèi)存變成進(jìn)程之后,操作系統(tǒng)要對(duì)該進(jìn)程進(jìn)行管理,即為其創(chuàng)建對(duì)應(yīng)的PCB對(duì)象,而進(jìn)程狀態(tài),本質(zhì)上就是PCB內(nèi)部的一個(gè)整形變量,不同的整形值就對(duì)應(yīng)不同的進(jìn)程狀態(tài)。
????????常見的進(jìn)程狀態(tài):運(yùn)行、掛起、阻塞、新建、就緒、等待、掛機(jī)、死亡。進(jìn)程的不同狀態(tài)本質(zhì)都是用來滿足不同的運(yùn)行場(chǎng)景的。
- 運(yùn)行隊(duì)列
進(jìn)程如何在CPU上運(yùn)行的:CPU在內(nèi)核上維護(hù)了一個(gè)運(yùn)行隊(duì)列,進(jìn)行對(duì)進(jìn)程的管理。讓進(jìn)程入隊(duì)列,本質(zhì)就是將該進(jìn)程的task_struct 結(jié)構(gòu)體對(duì)象放入運(yùn)行隊(duì)列之中。
一個(gè)CPU就一個(gè)運(yùn)行隊(duì)列
- 進(jìn)程狀態(tài)
- 運(yùn)行狀態(tài):
進(jìn)程PCB在運(yùn)行隊(duì)列里就是運(yùn)行狀態(tài),不是說這個(gè)進(jìn)程正在運(yùn)行,才是運(yùn)行狀態(tài)。
狀態(tài)是進(jìn)程內(nèi)部的屬性,所有的屬性在PCB里
進(jìn)程不只是占用CPU資源,也有可能隨時(shí)要外設(shè)資源
- 阻塞狀態(tài):
進(jìn)程不在運(yùn)行隊(duì)列之中,進(jìn)程不能直接被調(diào)度,而是在等待外設(shè)資源的狀態(tài),進(jìn)程的PCB就被放在硬件的等待隊(duì)列中。本質(zhì)是對(duì)tack_struct對(duì)象放到不同的隊(duì)列中!
綜上,所謂的進(jìn)程不同的狀態(tài),本質(zhì)是進(jìn)程在不同的隊(duì)列之中,等待某種資源
- 掛起狀態(tài):
如果系統(tǒng)中存在許多進(jìn)程,進(jìn)程短期內(nèi)不會(huì)被調(diào)度,代碼和數(shù)據(jù)在短期內(nèi)不會(huì)被執(zhí)行,此時(shí)如果內(nèi)存空間不足,操作系統(tǒng)就可以把代碼和數(shù)據(jù)暫時(shí)保存到磁盤上,節(jié)省一部分空間,該進(jìn)程暫時(shí)被掛起了,這就是掛起狀態(tài)。
對(duì)于阻塞狀態(tài)和掛起狀態(tài),阻塞不一定掛起,掛起一定是阻塞。
??Linux進(jìn)程狀態(tài)
我們Linux進(jìn)程狀態(tài),可以用kernel源代碼查看:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
- R運(yùn)行狀態(tài)(running) : 并不意味著進(jìn)程一定在運(yùn)行中,它表明進(jìn)程要么是在運(yùn)行中要么在運(yùn)行隊(duì)列里。
- S睡眠狀態(tài)(sleeping): 意味著進(jìn)程在等待事件完成(這里的睡眠有時(shí)候也叫做可中斷睡眠(interruptible sleep))。
- D磁盤休眠狀態(tài)(Disk sleep)有時(shí)候也叫不可中斷睡眠狀態(tài)(uninterruptible sleep),在這個(gè)狀態(tài)的進(jìn)程通常會(huì)等待IO的結(jié)束。
- T停止?fàn)顟B(tài)(stopped): 可以通過發(fā)送 SIGSTOP 信號(hào)給進(jìn)程來停止(T)進(jìn)程。這個(gè)被暫停的進(jìn)程可以通過發(fā)送 SIGCONT 信號(hào)讓進(jìn)程繼續(xù)運(yùn)行。
- X死亡狀態(tài)(dead):這個(gè)狀態(tài)只是一個(gè)返回狀態(tài),你不會(huì)在任務(wù)列表里看到這個(gè)狀態(tài)。
- z僵尸狀態(tài)(zombie):這個(gè)狀態(tài)是一個(gè)已經(jīng)運(yùn)行完的子進(jìn)程等待父進(jìn)程回收它的返回信息。
?
那么我們可以親自操作來查看各種狀態(tài)
ps aux / ps axj //命令
那咱們看看Linux各種狀態(tài)下的樣子:
??R運(yùn)行狀態(tài)?
創(chuàng)建Makefile:
創(chuàng)建myprocess.c:
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1);
{
int a = 0;
a = 1+1;
}
return 0;
}
這里博主沒有顯示,因?yàn)闆]有運(yùn)行。
??S睡眠狀態(tài)?
?創(chuàng)建Makefile:
創(chuàng)建myprocess.c:
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1);
{
int a = 0;
a = 1+1;
}
return 0;
}
??兩個(gè)特殊進(jìn)程
進(jìn)程退出的時(shí)候不能立即釋放該進(jìn)程對(duì)應(yīng)的資源!保存一段時(shí)間,讓對(duì)應(yīng)的父進(jìn)程/操作系統(tǒng)進(jìn)行讀取。
??僵尸進(jìn)程?
????????進(jìn)程退出了,但退出信息沒有父進(jìn)程或者OS被回收,那么此時(shí)該進(jìn)程就處于僵尸進(jìn)程。咱們演示一下效果。
創(chuàng)建myproc.c:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if(id == 0)
{
// 子進(jìn)程
printf("after fork, 我是子進(jìn)程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id);
sleep(5);
exit(1);
}
else{
// 父進(jìn)程
while(1){
printf("after fork, 我是父進(jìn)程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id);
sleep(1);
}
}
return 0;
}
創(chuàng)建Makefile:
myproc:myproc.c
gcc -o myproc myproc.c
.PHONY:clean
clean:
rm -f myproc.c
運(yùn)行結(jié)果:
總結(jié):
- 僵死狀態(tài)(Zombies)是一個(gè)比較特殊的狀態(tài)。當(dāng)進(jìn)程退出并且父進(jìn)程沒有讀取到子進(jìn)程退出的返回代碼時(shí)就會(huì)產(chǎn)生僵死(尸)進(jìn)程
- 僵死進(jìn)程會(huì)以終止?fàn)顟B(tài)保持在進(jìn)程表中,并且會(huì)一直在等待父進(jìn)程讀取退出狀態(tài)代碼。所以,只要子進(jìn)程退出,父進(jìn)程還在運(yùn)行,但父進(jìn)程沒有讀取子進(jìn)程狀態(tài),子進(jìn)程進(jìn)入Z狀態(tài)。
僵尸進(jìn)程的危害:
- 進(jìn)程的退出狀態(tài)必須被維持下去,因?yàn)樗嬖V關(guān)心它的進(jìn)程(父進(jìn)程),你交給我的任務(wù),我辦的怎么樣了??筛高M(jìn)程如果一直不讀取,那子進(jìn)程就一直處于Z狀態(tài)?是的!
- 維護(hù)退出狀態(tài)本身就是要用數(shù)據(jù)維護(hù),也屬于進(jìn)程基本信息,所以保存在task_struct(PCB)中,換句話說, Z狀態(tài)一直不退出, PCB一直都要維護(hù)?是的!
- 那一個(gè)父進(jìn)程創(chuàng)建了很多子進(jìn)程,就是不回收,是不是就會(huì)造成內(nèi)存資源的浪費(fèi)?是的!因?yàn)閿?shù)據(jù)結(jié)構(gòu)對(duì)象本身就要占用內(nèi)存,想想C中定義一個(gè)結(jié)構(gòu)體變量(對(duì)象),是要在內(nèi)存的某個(gè)位置進(jìn)行開辟空間!
- 內(nèi)存泄漏
??孤兒進(jìn)程?
父進(jìn)程先退出,子進(jìn)程就稱之為"孤兒進(jìn)程"
創(chuàng)建myproc.c:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("before fork: I am a prcess, pid: %d, ppid: %d\n", getpid(), getppid());
sleep(5);
printf("開始創(chuàng)建進(jìn)程啦!\n");
sleep(1);
pid_t id = fork();
if (id < 0) return 1;
else if (id == 0)
{
// 子進(jìn)程
while (1) {
printf("after fork, 我是子進(jìn)程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id);
sleep(1);
}
}
else {
// 父進(jìn)程
while (1) {
printf("after fork, 我是父進(jìn)程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id);
sleep(1);
}
}
return 0;
}
創(chuàng)建Makefile:
myproc:myproc.c
gcc -o myproc myproc.c
.PHONY:clean
clean:
rm -f myproc.c
運(yùn)行結(jié)果:
??進(jìn)程優(yōu)先級(jí)
??優(yōu)先級(jí)概念
- 優(yōu)先級(jí)
即獲取資源的先后順序和先后被執(zhí)行的能力。優(yōu)先級(jí)高的先獲得和執(zhí)行,優(yōu)先級(jí)低的反之。
存在的原因:資源太少,需要資源分配。
cpu資源分配的先后順序,就是指進(jìn)程的優(yōu)先權(quán)(priority)。優(yōu)先權(quán)高的進(jìn)程有優(yōu)先執(zhí)行權(quán)利。配置進(jìn)程優(yōu)先權(quán)對(duì)多任務(wù)環(huán)境的linux很有用,可以改善系統(tǒng)性能。還可以把進(jìn)程運(yùn)行到指定的CPU上,這樣一來,把不重要的進(jìn)程安排到某個(gè)CPU,可以大大改善系統(tǒng)整體性能。
- Linux優(yōu)先級(jí)
優(yōu)先級(jí)本質(zhì)就是PCB里面一個(gè)整數(shù)數(shù)字(或者幾個(gè)整型數(shù)字)
Linux優(yōu)先級(jí)有一個(gè)特點(diǎn):很快
??查看系統(tǒng)進(jìn)程
在linux或者unix系統(tǒng)中,用ps –l/ps -al命令則會(huì)類似輸出以下幾個(gè)內(nèi)容:
- UID : 代表執(zhí)行者的身份
- PID : 代表這個(gè)進(jìn)程的代號(hào)
- PPID :代表這個(gè)進(jìn)程是由哪個(gè)進(jìn)程發(fā)展衍生而來的,亦即父進(jìn)程的代號(hào)
- PRI :代表這個(gè)進(jìn)程可被執(zhí)行的優(yōu)先級(jí),其值越小越早被執(zhí)行
- NI :代表這個(gè)進(jìn)程的nice值
??PRI和NI
Linux中由兩個(gè)整型數(shù)字決定優(yōu)先級(jí):PRI(priority)和NI(nice)
最終優(yōu)先級(jí) = 老的優(yōu)先級(jí)(PRI)+ NI(nice)
注意:
????????Linux下的老的優(yōu)先級(jí)PRI默認(rèn)值是80!而NI取值是有范圍,取值范圍是[-20,19]。也就意味著優(yōu)先級(jí)是有取值范圍的[80-21,80+19]
????????在Linux下支持進(jìn)程在運(yùn)行中進(jìn)行優(yōu)先級(jí)調(diào)整的,調(diào)整的策略就是更改nice完成的,也就是說會(huì)受到nice值影響(但是一般情況下不修改),但是大部分情況下,nice值是默認(rèn)的也就是0。
這里的PRI優(yōu)先級(jí)是80,NI值是0
??top命令更改nice
步驟1:sudo top
步驟2:進(jìn)入top后輸入r然后在輸入進(jìn)程的pid(進(jìn)入進(jìn)程)輸入要修改nice的值
myproc.c代碼:
初始NI和PRI:
用top命令進(jìn)行修改:(先輸入命令sudo top后在輸入r,在輸入進(jìn)程的PID):
開始修改:(找到進(jìn)程編號(hào))
看到這個(gè)界面就可以開始更改NI值了:
這里博主就不修改了,但是要注意一些細(xì)節(jié):
調(diào)優(yōu)先級(jí)并不意味著你可以隨便調(diào),這是操作系統(tǒng)不允許的,會(huì)導(dǎo)致調(diào)度失衡。所以有著一定的取值范圍
nice的取值范圍是[-20,19],一共40個(gè)數(shù)字
- 需要注意的是:每次調(diào)動(dòng)優(yōu)先級(jí)時(shí)候,PID值都會(huì)從默認(rèn)值80開始,NI值從0開始,不存在累加累減情況。
??特性
- 競(jìng)爭(zhēng)性: 系統(tǒng)進(jìn)程數(shù)目眾多,而CPU資源只有少量,甚至1個(gè),所以進(jìn)程之間是具有競(jìng)爭(zhēng)屬性的。為了高效完成任務(wù),更合理競(jìng)爭(zhēng)相關(guān)資源,便具有了優(yōu)先級(jí)
- 獨(dú)立性: 多進(jìn)程運(yùn)行,需要獨(dú)享各種資源,多進(jìn)程運(yùn)行期間互不干擾
- 并行: 多個(gè)進(jìn)程在多個(gè)CPU下分別,同時(shí)進(jìn)行運(yùn)行,這稱之為并行
- 并發(fā): 多個(gè)進(jìn)程在一個(gè)CPU下采用進(jìn)程切換的方式,在一段時(shí)間之內(nèi),讓多個(gè)進(jìn)程都得以推進(jìn),稱之為并發(fā)
這里的獨(dú)立性對(duì)于父進(jìn)程和子進(jìn)程是否還是存在?yes
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if (id == 0)
{
while (1)
{
printf("this is child process,pid: %d,ppid:%d\n", getpid(), getppid());
sleep(1);
int* p = NULL;
*p = 100;//野指針
}
}
else
{
while (1)
{
printf("this is parent process,pid:%d,ppid:%d\n", getpid(), getppid());
sleep(1);
}
}
}
運(yùn)行結(jié)果:
子進(jìn)程崩潰并沒有影響父進(jìn)程。
??進(jìn)程切換
- 1.并發(fā)
- 多進(jìn)程在同一CPU下通過采用進(jìn)程不斷切換的方式讓一個(gè)單CPU計(jì)算機(jī)在一個(gè)時(shí)間段內(nèi)同時(shí)讓多個(gè)進(jìn)程代碼同時(shí)推進(jìn)的現(xiàn)象稱為并發(fā)
采用進(jìn)程切換的方式在一個(gè)時(shí)間段內(nèi)不同的進(jìn)程都可以把代碼跑起來,同時(shí)推進(jìn)
- 2.進(jìn)程如何切換
- 一個(gè)CPU里面存在一套硬件寄存器,宏觀上寄存器分為用戶可見,用戶不可見
- 計(jì)算機(jī)調(diào)度某個(gè)進(jìn)程時(shí),CPU會(huì)把這個(gè)進(jìn)程的PCB地址加載到某個(gè)寄存器,也就是說,CPU內(nèi)有寄存器可以只找到進(jìn)程的PCB地址
- CPU里有一個(gè)eip寄存器(PC指針),指向當(dāng)前執(zhí)行指令的下一條指令的地址。
而進(jìn)程運(yùn)行的時(shí)候一定會(huì)產(chǎn)生很多的臨時(shí)數(shù)據(jù),但這些臨時(shí)數(shù)據(jù)只屬于當(dāng)前進(jìn)程,雖然CPU內(nèi)部只有一套寄存器硬件,但是寄存器保存的數(shù)據(jù)只屬于當(dāng)前進(jìn)程,也就是說,寄存器硬件不是寄存器內(nèi)的數(shù)據(jù),這是兩碼事,寄存器被所有進(jìn)程共享,但是寄存器里的數(shù)據(jù)時(shí)每個(gè)進(jìn)程各自私有的。
時(shí)間片引出:
- 進(jìn)程在運(yùn)行的時(shí)候占有CPU,但是卻不是一直占有到進(jìn)程結(jié)束,進(jìn)程都有自己的時(shí)間片!因?yàn)闀r(shí)間片的存在,進(jìn)程會(huì)出現(xiàn)沒有被執(zhí)行完就被拿下去的情況,這時(shí)候問題來了:這個(gè)進(jìn)程下一次如何在次回到CPU繼續(xù)運(yùn)行:
- 進(jìn)程切換的時(shí)候,需要先進(jìn)行上下文保護(hù),這里的上下文指的是CPU里的寄存器的數(shù)據(jù),而不是寄存器,這里簡單理解為臨時(shí)數(shù)據(jù)保存至PCB里,而當(dāng)進(jìn)程恢復(fù)運(yùn)行的時(shí)候,要進(jìn)行上下文的恢復(fù),該進(jìn)程在次回到CPU繼續(xù)運(yùn)行時(shí),重新加載恢復(fù)這些數(shù)據(jù)。
???結(jié)束語
? ? ? ?今天內(nèi)容就到這里啦,時(shí)間過得很快,大家沉下心來好好學(xué)習(xí),會(huì)有一定的收獲的,大家多多堅(jiān)持,嘻嘻,成功路上注定孤獨(dú),因?yàn)閳?jiān)持的人不多。那請(qǐng)大家舉起自己的小手給博主一鍵三連,有你們的支持是我最大的動(dòng)力??????,回見。文章來源:http://www.zghlxwxcb.cn/news/detail-763711.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-763711.html
到了這里,關(guān)于【Linux】進(jìn)程狀態(tài)、進(jìn)程優(yōu)先級(jí)和進(jìn)程切換的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!