如果不改變自己,就別把跨年搞的和分水嶺一樣,記住你今年是什么吊樣,明年就還會(huì)是什么吊樣?。。?/mark>
一、馮諾依曼體系結(jié)構(gòu)(硬件)
1.馮諾依曼體系結(jié)構(gòu)中的存儲(chǔ)器指的是內(nèi)存,帶電存儲(chǔ),具有掉電易失的特點(diǎn)。
2.CPU中含有能夠解釋計(jì)算機(jī)指令的指令集,指令集又可分為精簡(jiǎn)指令集和復(fù)雜指令集,這也正是為什么你的程序能夠運(yùn)行起來的原因,因?yàn)镃PU認(rèn)識(shí)并理解你的二進(jìn)制程序代碼,你的二進(jìn)制程序會(huì)被CPU認(rèn)為是一堆指令的集合,CPU直接執(zhí)行這些二進(jìn)制指令就OK了。
3.某些外部設(shè)備例如磁盤、網(wǎng)卡等,既屬于輸入設(shè)備又屬于輸出設(shè)備,輸入和輸出的對(duì)象是針對(duì)于內(nèi)存或CPU來講的,例如我們用鍵盤將數(shù)據(jù)輸入到內(nèi)存中,磁盤也可以將數(shù)據(jù)取出來輸入到內(nèi)存中,也可以將內(nèi)存中的數(shù)據(jù)輸出到磁盤上進(jìn)行存儲(chǔ),所以判斷一個(gè)設(shè)備是否為輸入,輸出設(shè)備,需要看數(shù)據(jù)在這個(gè)設(shè)備中的流向,流向CPU為輸入設(shè)備,流出CPU為輸出設(shè)備,既能流入又能流出就是輸入輸出設(shè)備。
4.CPU在讀取和寫入的時(shí)候,在數(shù)據(jù)層面,只和內(nèi)存打交道,不和外設(shè)直接溝通,這樣有利于提高整個(gè)計(jì)算機(jī)的運(yùn)行效率。
5.磁盤上的文件程序想要運(yùn)行,必須要加載到內(nèi)存里面,因?yàn)镃PU只能從內(nèi)存中訪問你寫的數(shù)據(jù)和代碼,我們平常所進(jìn)行的編程其實(shí)就是在為CPU準(zhǔn)備數(shù)據(jù)和代碼,等CPU過來讀取這些代碼并執(zhí)行他,這些都是馮諾依曼體系結(jié)構(gòu)所決定的
下面從軟件數(shù)據(jù)流的角度來更深入的理解馮諾依曼硬件結(jié)構(gòu)體系:
1.
如果我向我的好友發(fā)送消息,從硬件結(jié)構(gòu)來看,前提應(yīng)該是我們各自都打開了QQ程序,并將QQ這個(gè)程序加載到了內(nèi)存里面,CPU會(huì)執(zhí)行QQ程序的代碼,我就可以通過代碼里面的scanf或cin等語(yǔ)句的執(zhí)行,利用鍵盤發(fā)送消息“你好呀!你今天吃飯沒?”等等消息,這些消息數(shù)據(jù)會(huì)由輸入設(shè)備鍵盤加載到內(nèi)存中的QQ程序里面,然后CPU對(duì)這些消息做出處理,將處理后的結(jié)果返回給內(nèi)存里面,然后這些消息會(huì)從內(nèi)存進(jìn)一步加載到外部設(shè)備網(wǎng)卡和顯示器等里面,我的朋友的筆記本的輸入設(shè)備網(wǎng)卡會(huì)接收這些消息,并將這些消息加載到他的內(nèi)存中的QQ程序里面,然后CPU做出信息的分析將結(jié)果返回到內(nèi)存里面,最后這些處理過后的信息會(huì)進(jìn)一步加載到我朋友筆記本上的顯示器中,這樣就完成了信息的發(fā)送和接收等。
2.
如果是發(fā)送文件,其實(shí)就是從磁盤這樣的外設(shè)中將信息加載到內(nèi)存中的QQ程序里面,然后通過網(wǎng)卡將信息傳輸過去,我的朋友就可以用他的網(wǎng)卡接收到這些信息,并把我發(fā)送的信息加載到內(nèi)存里面,最后在輸出設(shè)備磁盤里面重新刷新,就會(huì)出現(xiàn)接收到的文件信息了。
二、操作系統(tǒng)(軟件)
1.操作系統(tǒng)是什么?
1.操作系統(tǒng)是一個(gè)進(jìn)行軟硬件資源管理的軟件
2.操作系統(tǒng)包括進(jìn)程管理,內(nèi)存管理,文件系統(tǒng),驅(qū)動(dòng)管理,這些都是操作系統(tǒng)對(duì)于軟件的管理,除了管理這些,操作系統(tǒng)還承擔(dān)管理馮諾依曼硬件體系結(jié)構(gòu)。
3.為什么操作系統(tǒng)要進(jìn)行管理呢?因?yàn)椴僮飨到y(tǒng)可以通過合理的對(duì)于軟硬件資源管理(手段),來為用戶提供良好的(穩(wěn)定的、安全的、高效的)執(zhí)行環(huán)境(目的)
2.如何理解管理(管理的本質(zhì))
1.
管理者和被管理者之間是一個(gè)什么樣的邏輯關(guān)系呢?就像我們?cè)诖髮W(xué)生活中的校長(zhǎng),我們很少直接與校長(zhǎng)進(jìn)行交互,但校長(zhǎng)依舊管理著我們,這是怎么做到的呢?還比如公司中的員工和CEO,CEO不會(huì)和員工直接對(duì)話、噓寒問暖等等,但公司依舊可以正常運(yùn)行,正常的被管理,這又是怎么做的呢?
2.
我們可以通過這樣的現(xiàn)象得出一個(gè)既定的事實(shí),那就是管理者和被管理者不需要直接進(jìn)行交互,管理者依舊能把被管理對(duì)象管理起來。
3.
首先管理者需要有重大事宜的決策能力,并且決策是要有依據(jù)的,同時(shí)管理者要擁有被管理對(duì)象的全部數(shù)據(jù),只要擁有了被管理對(duì)象的數(shù)據(jù),通過數(shù)據(jù)的變化和更新,管理者就可以與之對(duì)應(yīng)做出管理的方案。
4.所以管理的本質(zhì)就是對(duì)數(shù)據(jù)做出管理
3.操作系統(tǒng)如何一直拿到硬件的數(shù)據(jù)?(驅(qū)動(dòng)程序的引出)
1.
我們?cè)谏厦嬲劦竭^,管理者和被管理者是不直接進(jìn)行交互的,就比如校長(zhǎng)是不和我們大學(xué)生直接進(jìn)行面對(duì)面的談?wù)摵徒涣鞯?,那么校方是如何拿到每一個(gè)大學(xué)生的數(shù)據(jù)呢?操作系統(tǒng)又是如何拿到以馮諾依曼體系為基礎(chǔ)的所有硬件結(jié)構(gòu)的數(shù)據(jù)呢?
2.
這都需要一個(gè)執(zhí)行者,執(zhí)行者負(fù)責(zé)拿到被管理者的全部信息,現(xiàn)實(shí)中的管理者可能就是我們的班長(zhǎng)或輔導(dǎo)員等等,他可以拿到我們的全部數(shù)據(jù),最后將這些數(shù)據(jù)統(tǒng)計(jì)匯報(bào)給校方,自然計(jì)算機(jī)中也需要這么一個(gè)執(zhí)行者,這個(gè)執(zhí)行者就是驅(qū)動(dòng)程序
3.
所以,驅(qū)動(dòng)程序會(huì)做兩件事情,第一件當(dāng)然是和被管理者也就是底層硬件直接接觸,拿到被管理者的所有數(shù)據(jù),第二件事情就是執(zhí)行管理者的命令也就是操作系統(tǒng)的命令,如何執(zhí)行,執(zhí)行什么等決策都是由管理者操作系統(tǒng)來決定的
4.
OS可以根據(jù)硬件的數(shù)據(jù)變化來命令驅(qū)動(dòng)程序?qū)τ布M(jìn)行相應(yīng)的管理,這樣就可以實(shí)現(xiàn)對(duì)硬件的管理,命令中樞在OS,驅(qū)動(dòng)程序既要將硬件數(shù)據(jù)返回給操作系統(tǒng),又要執(zhí)行操作系統(tǒng)的命令以此來管理好硬件資源。
4.操作系統(tǒng)對(duì)于龐大的軟硬件的數(shù)據(jù)量如何進(jìn)行管理?(先描述,再組織)
1.
我們知道計(jì)算機(jī)的底層硬件是非常多的,光單個(gè)硬件的數(shù)據(jù)量其實(shí)就已經(jīng)非常多了,更別說所有的底層硬件的數(shù)據(jù)了,那將是非常龐大的數(shù)字,操作系統(tǒng)對(duì)于驅(qū)動(dòng)程序返回來的如此龐大的數(shù)據(jù)量一定會(huì)非常的頭疼,如果沒有合理的管理,這么多的數(shù)據(jù)一定會(huì)亂起來的,計(jì)算機(jī)就無(wú)法正常運(yùn)行了。
2.
例如校方獲得學(xué)生的龐大信息之后,他一定不會(huì)拿許許多多的表格和文件來存放這些信息,這樣的效率非常的低,所以校方會(huì)有自己的一個(gè)系統(tǒng),這個(gè)系統(tǒng)里面會(huì)存儲(chǔ)學(xué)生的信息,以這樣的方式來對(duì)學(xué)生進(jìn)行管理,所以可以總結(jié)出來管理的方法本質(zhì)邏輯就是先描述,再組織,校方通過一個(gè)程序,例如這個(gè)程序利用了鏈表將學(xué)生信息存儲(chǔ)起來,那么每個(gè)節(jié)點(diǎn)就需要描述好每個(gè)學(xué)生,入學(xué)時(shí)間,高考成績(jī),在校表現(xiàn)等等,然后將節(jié)點(diǎn)組織成鏈表,通過數(shù)據(jù)結(jié)構(gòu)的方式來將學(xué)生的信息組織起來,進(jìn)行統(tǒng)一的管理。
3.
所以,所有的“管理”,本質(zhì)邏輯都是“先描述,再組織?!泵枋鍪蔷幊陶Z(yǔ)言的話題,組織是數(shù)據(jù)結(jié)構(gòu)的話題,組織其實(shí)就是對(duì)被管理對(duì)象進(jìn)行建模的過程
4.
操作系統(tǒng)對(duì)于硬件是先描述再組織進(jìn)行管理的,那對(duì)于軟件的管理呢?進(jìn)程、文件系統(tǒng)、內(nèi)存、驅(qū)動(dòng)、系統(tǒng)調(diào)用接口等軟件,操作系統(tǒng)又是怎么管理呢?答案還是“先描述,再組織”,操作系統(tǒng)依舊通過獲得他們的數(shù)據(jù),通過類或結(jié)構(gòu)體(因?yàn)長(zhǎng)inux內(nèi)核是用C語(yǔ)言寫的)將這些獲得的數(shù)據(jù)描述起來,然后再通過鏈表或者其他更高效的數(shù)據(jù)結(jié)構(gòu)來將這些數(shù)據(jù)組織起來,然后進(jìn)行管理。
5.人能管理事物,人也能管理人。軟件能管理硬件,軟件也能管理軟件。
5.計(jì)算機(jī)的軟硬件結(jié)構(gòu)體系(計(jì)算機(jī)的層狀結(jié)構(gòu))
1.
首先操作系統(tǒng)是不相信任何的用戶的,如果用戶隨意篡改操作系統(tǒng)的源代碼,那計(jì)算機(jī)就無(wú)法正常的使用,并且如果這些源代碼被公開,這很有可能讓操作系統(tǒng)受到 “傷害” 所以操作系統(tǒng)是無(wú)法分辨一個(gè)用戶會(huì)不會(huì)亂來的,那么操作系統(tǒng)就有保護(hù)自己的義務(wù),但同時(shí)操作系統(tǒng)又需要對(duì)上服務(wù)好用戶,所以可以得出來一個(gè)矛盾,操作系統(tǒng)不可以直接開放給用戶使用,但是操作系統(tǒng)還需要對(duì)用戶開放良好的服務(wù)。
2.
這時(shí),操作系統(tǒng)會(huì)提供給用戶一些系統(tǒng)調(diào)用接口,這些接口可以被用戶所調(diào)用,如果用戶的操作不合法,那就不能正常調(diào)用到這些系統(tǒng)接口,我們的請(qǐng)求就不會(huì)被操作系統(tǒng)所接收,如此一來,這些系統(tǒng)調(diào)用接口就可以變相的保護(hù)操作系統(tǒng),并且還可以給用戶提供服務(wù)。
3.
這些系統(tǒng)調(diào)用接口,都是由C語(yǔ)言寫出來的,所以這些接口都是C式的接口,說白了就是操作系統(tǒng)通過C語(yǔ)言給我們提供了一些系統(tǒng)級(jí)別的函數(shù)調(diào)用的接口。
4.
當(dāng)然,這些接口普通人是不會(huì)使用的,隨之在這些系統(tǒng)級(jí)別的接口外面一層又開放了用戶操作接口,用戶可以通過自身的一些操作來調(diào)用這些用戶操作接口,以此使得操作系統(tǒng)能夠更加先進(jìn)的服務(wù)用戶。
6.系統(tǒng)調(diào)用和庫(kù)函數(shù)的區(qū)別(上下層關(guān)系)
1.
在開發(fā)角度,操作系統(tǒng)對(duì)外會(huì)表現(xiàn)為一個(gè)整體,但是會(huì)暴露自己的部分接口,供上層開發(fā)使用,這部分由操作系統(tǒng)提供的接口,叫做系統(tǒng)調(diào)用接口。
2.
系統(tǒng)調(diào)用在使用上,功能比較基礎(chǔ),對(duì)用戶的要求相對(duì)也比較高,所以,有心的開發(fā)者可以對(duì)部分系統(tǒng)調(diào)用進(jìn)行適度封裝,從而形成庫(kù),有了庫(kù),就很有利于上層用戶或者開發(fā)者進(jìn)行二次開發(fā),許多的C/C++庫(kù)其實(shí)就是系統(tǒng)調(diào)用接口封裝得來的,所以兩者其實(shí)是上下層的關(guān)系。
三、進(jìn)程
1.OS如何管理進(jìn)程?(先描述,再組織:進(jìn)程控制塊PCB)
1.
首先程序的本質(zhì)其實(shí)就是文件,該文件可以被永久性的存放在磁盤當(dāng)中,一個(gè)加載到內(nèi)存中的程序,我們就稱之為進(jìn)程,在windows下我們可以看到許多進(jìn)程,包括正在運(yùn)行的和后臺(tái)運(yùn)行的進(jìn)程,對(duì)于如此多的進(jìn)程,操作系統(tǒng)是一定要進(jìn)行管理的,那該如何進(jìn)行管理呢?
2.
管理的本質(zhì)是對(duì)數(shù)據(jù)進(jìn)行管理,管理的邏輯是先描述,再組織,在Linux中,操作系統(tǒng)會(huì)通過task_struct結(jié)構(gòu)體task_struct(轉(zhuǎn)載博客園童嫣博主的文章)將每一個(gè)進(jìn)程的所有屬性抽象化描述起來,Linux操作系統(tǒng)再通過雙向循環(huán)鏈表的數(shù)據(jù)結(jié)構(gòu)將數(shù)量龐大的進(jìn)程進(jìn)行組織,這樣的話,管理進(jìn)程就變成了對(duì)進(jìn)程所對(duì)應(yīng)的PCB進(jìn)行相關(guān)的管理。
3.
進(jìn)程的數(shù)據(jù)被存放在一個(gè)叫做進(jìn)程控制塊的數(shù)據(jù)結(jié)構(gòu)當(dāng)中,進(jìn)程控制塊又可以稱之為PCB(process control block),進(jìn)程控制塊中包含進(jìn)程標(biāo)識(shí)符、上下文數(shù)據(jù)、進(jìn)程調(diào)度信息、進(jìn)程控制信息、IO狀態(tài)信息以及進(jìn)程對(duì)應(yīng)的磁盤代碼等,Linux操作系統(tǒng)中進(jìn)程控制塊其實(shí)就是struct task_struct結(jié)構(gòu)體,windows操作系統(tǒng)中進(jìn)程控制塊其實(shí)就是執(zhí)行體進(jìn)程塊(struct _EPROCESS )
4.
進(jìn)程和程序相比進(jìn)程是具有動(dòng)態(tài)屬性的,程序僅僅只是一堆代碼形成的文件而已,所以我們將進(jìn)程提煉出來,進(jìn)程=進(jìn)程控制塊(內(nèi)核數(shù)據(jù)結(jié)構(gòu) struct task_struct)+ 進(jìn)程對(duì)應(yīng)的磁盤代碼
2.查看進(jìn)程的兩種方式
進(jìn)程在調(diào)度運(yùn)行的時(shí)候,進(jìn)程就具有動(dòng)態(tài)屬性!
一、ps指令
ppid父進(jìn)程id,pid是進(jìn)程id,pgid是進(jìn)程組id,sid會(huì)話id,TTY終端,STAT狀態(tài),uid用戶id,COMMAND代表哪個(gè)進(jìn)程
[wyn@VM-8-2-centos test_dir]$ ps ajx | head -1 && ps ajx | grep "myproc"
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
12672 15583 15583 12672 pts/1 15583 S+ 1001 0:00 ./myproc
13962 16742 16741 13962 pts/0 16741 S+ 1001 0:00 grep --color=auto myproc
二、ls指令
我們還可以通過根目錄下的proc目錄來查看進(jìn)程,我們的進(jìn)程也可以被當(dāng)作一個(gè)目錄,Linux下一切皆文件
ls /proc/進(jìn)程的pid
三、如果刪除掉了進(jìn)程對(duì)應(yīng)的磁盤上的二進(jìn)制可執(zhí)行程序,進(jìn)程還會(huì)運(yùn)行嗎?
答案是沒有任何影響,完全可以繼續(xù)運(yùn)行,所以理論上來講,一旦程序加載到內(nèi)存之后,進(jìn)程和程序就沒關(guān)系了,但是進(jìn)程中的可執(zhí)行程序文件會(huì)冒紅。
4.殺掉進(jìn)程
kill -l --- 查看kill指令選項(xiàng)
kill -9 + 進(jìn)程id --- 殺掉進(jìn)程
3.與進(jìn)程相關(guān)的系統(tǒng)調(diào)用
3.1 getpid() && getppid()(獲取進(jìn)程的標(biāo)識(shí)符)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("我是一個(gè)進(jìn)程!,我的進(jìn)程id是%d,我的父進(jìn)程pid是:%d\n",getpid(),getppid());
10 sleep(1);
11 }
12 return 0;
13 }
1.
我們可以看到進(jìn)程的id隨著我們的多次運(yùn)行會(huì)不斷的變化,但是父進(jìn)程的id一直不變,并且我們還查看到了父進(jìn)程的名字是bash,shell有多種,但bash是最常見的一種,bash就是centos系統(tǒng)下的shellLinux下有幾種shell(轉(zhuǎn)載自cunchi4221
博主的文章)所以當(dāng)前進(jìn)程的父進(jìn)程就是命令行解釋器bash,bash的進(jìn)程id,系統(tǒng)會(huì)自動(dòng)給我們分配好,如果我們殺掉了命令行解釋器bash這個(gè)進(jìn)程的話,我們就會(huì)自動(dòng)退出xshell工具。
2.
下面便可以看到父進(jìn)程id始終不變,我的代碼對(duì)應(yīng)的進(jìn)程id會(huì)因?yàn)槌绦虻亩啻芜\(yùn)行而變化,并且我的進(jìn)程的父進(jìn)程是bash,所以我們可以得出結(jié)論:命令行上啟動(dòng)的進(jìn)程,一般它的父進(jìn)程沒有特殊情況的話,都是bash!
3.2 fork()(創(chuàng)建進(jìn)程)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main()
6 {
7 // 創(chuàng)建子進(jìn)程 -- fork是一個(gè)函數(shù) -- 函數(shù)執(zhí)行前:只有一個(gè)父進(jìn)程(bash派生的)-- 函數(shù)執(zhí)行后:就會(huì)有父進(jìn)程和父進(jìn)程創(chuàng)建的子進(jìn)程。
8 fork();
9
10 printf("我是一個(gè)進(jìn)程!,我的進(jìn)程id是%d,我的父進(jìn)程pid是:%d\n",getpid(),getppid());
11 sleep(3);
12
13 return 0;
14 }
1.
由程序運(yùn)行結(jié)果可以看到,printf被執(zhí)行了兩次,這是怎么一回事???這其實(shí)是因?yàn)樽舆M(jìn)程進(jìn)程做了父進(jìn)程一模一樣的事情,他把代碼也執(zhí)行了一遍。
下面的7088進(jìn)程的父進(jìn)程就是1492,1492實(shí)際上就是bash,7088的子進(jìn)程是7089,這個(gè)進(jìn)程就是fork函數(shù)創(chuàng)建出來的子進(jìn)程,這個(gè)子進(jìn)程的父進(jìn)程是7088,也就是bash的子進(jìn)程,所以7088即是bash的兒子,又是fork產(chǎn)生的進(jìn)程7089的爹。
2.
通過man手冊(cè)在底行中輸入/加查找內(nèi)容就可以查看到fork函數(shù)的返回值,它的意思是創(chuàng)建子進(jìn)程如果成功的話,就會(huì)將子進(jìn)程pid返回給父進(jìn)程,數(shù)字0會(huì)被返回給子進(jìn)程,如果創(chuàng)建失敗的話,返回-1給父進(jìn)程,沒有子進(jìn)程的創(chuàng)建。
下面我們?cè)賮砜匆欢蝔ork接口的常用形式的代碼和其運(yùn)行結(jié)果
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main()
6 {
7 // 創(chuàng)建子進(jìn)程 -- fork是一個(gè)函數(shù) -- 函數(shù)執(zhí)行前:只有一個(gè)父進(jìn)程(bash派生的)-- 函數(shù)執(zhí)行后:就會(huì)有父進(jìn)程和父進(jìn)程創(chuàng)建的子進(jìn)程。
8 pid_t ret=fork();
9 //fork使用后一般要用if進(jìn)行分流
10 if(ret==0)
11 {
12 // 子進(jìn)程
13 while(1)
14 {
15 printf("我是一個(gè)進(jìn)程!,我的進(jìn)程id是%d,我的父進(jìn)程pid是:%d,ret是:%d\n",getpid(),getppid(),ret);
16 sleep(1);
17 }
18
19 }
20 else if(ret>0)
21 {
22 // 父進(jìn)程
23 while(1)
24 {
25 printf("我是一個(gè)進(jìn)程!,我的進(jìn)程id是%d,我的父進(jìn)程pid是:%d,ret是:%d\n",getpid(),getppid(),ret);
26 sleep(2);
27 }
28 }
29 else
30 {
31
32 }
33 return 0;
34 }
3.
fork之后,會(huì)有父進(jìn)程和子進(jìn)程兩個(gè)進(jìn)程在執(zhí)行后續(xù)的代碼,并且后續(xù)的代碼被父子進(jìn)程共享,我們可以通過返回值的不同,讓兩個(gè)進(jìn)程執(zhí)行后續(xù)共享代碼的不同部分。
我們也可以通過這樣的手段來讓兩個(gè)進(jìn)程執(zhí)行不同的任務(wù),這就是所謂的并發(fā)式的編程。
四、進(jìn)程狀態(tài)
1.普遍的操作系統(tǒng)層面:理解總結(jié)進(jìn)程狀態(tài)(運(yùn)行、阻塞、掛起狀態(tài))
1.
計(jì)算機(jī)在開機(jī)的時(shí)候,操作系統(tǒng)就會(huì)被加載到內(nèi)存里面,磁盤中的程序在運(yùn)行的時(shí)候也會(huì)被加載到內(nèi)存里面,實(shí)際上是加載到操作系統(tǒng)內(nèi)部,受操作系統(tǒng)的管理,我們知道程序運(yùn)行的時(shí)候,是需要CPU進(jìn)行讀取進(jìn)程的代碼并計(jì)算的,但進(jìn)程的數(shù)量一定會(huì)比CPU多,那CPU該怎么一個(gè)個(gè)的讀取進(jìn)程代碼并計(jì)算呢?答案是通過運(yùn)行隊(duì)列(數(shù)據(jù)結(jié)構(gòu))來對(duì)進(jìn)程的運(yùn)行進(jìn)行管理。
2.一個(gè)CPU匹配一個(gè)運(yùn)行隊(duì)列
3.
讓進(jìn)程入隊(duì)列,等待CPU資源。本質(zhì):將該進(jìn)程的task_struct結(jié)構(gòu)體對(duì)象放入CPU的運(yùn)行隊(duì)列struct runqueue中。操作系統(tǒng)操作的不是加載到內(nèi)存中的程序,操作的是進(jìn)程對(duì)應(yīng)的PCB(進(jìn)程控制塊,內(nèi)核數(shù)據(jù)結(jié)構(gòu))。
4.
CPU進(jìn)行進(jìn)程的調(diào)度,其實(shí)就是從自己的運(yùn)行隊(duì)列里面,找到進(jìn)程對(duì)應(yīng)的PCB,然后執(zhí)行進(jìn)程對(duì)應(yīng)的代碼和數(shù)據(jù)
5.
進(jìn)程的運(yùn)行狀態(tài)指的并不是這個(gè)進(jìn)程正在被運(yùn)行,因?yàn)檫@個(gè)數(shù)據(jù)是沒有意義的,CPU太快了,幾微秒就可以運(yùn)行完一個(gè)進(jìn)程,而是指的是這個(gè)進(jìn)程的PCB在CPU的運(yùn)行隊(duì)列runqueue當(dāng)中,只要這個(gè)進(jìn)程在運(yùn)行隊(duì)列里,那么這個(gè)進(jìn)程的狀態(tài)就是運(yùn)行狀態(tài)
6.
進(jìn)程的狀態(tài)其實(shí)就是進(jìn)程內(nèi)部的屬性,那么這個(gè)狀態(tài)其實(shí)就是存在于進(jìn)程對(duì)應(yīng)的PCB當(dāng)中,狀態(tài)在PCB里面其實(shí)就是一些整數(shù),每個(gè)整數(shù)對(duì)應(yīng)不同的狀態(tài),可以用#define R 1類似這樣的表示來區(qū)分不同的進(jìn)程狀態(tài),如下Linux內(nèi)核源代碼所示:
/*
* 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 */
};
7.
不要只以為,進(jìn)程只會(huì)等待(占用)CPU資源,進(jìn)程也可能隨時(shí)隨地,占用外設(shè)資源!
8.
進(jìn)程或多或少都要訪問硬件,例如我們平常代碼所寫的printf、cout要訪問顯示器,對(duì)文件進(jìn)行IO要訪問磁盤,scanf、cin要訪問鍵盤,但這些外設(shè)的運(yùn)行速度是很慢的,另一方面,這些外設(shè)的數(shù)量也是較少的,所以很有可能出現(xiàn)多個(gè)進(jìn)程訪問一個(gè)硬件的情況,但這個(gè)硬件一次只能服務(wù)一個(gè)進(jìn)程,所以其他進(jìn)程就需要排隊(duì)。
9.
當(dāng)CPU調(diào)度的某個(gè)進(jìn)程需要訪問外設(shè)時(shí),那操作系統(tǒng)就會(huì)把這個(gè)進(jìn)程放到硬件的結(jié)構(gòu)體描述里面的等待隊(duì)列task_struct * queue里面,直到硬件準(zhǔn)備就緒,此時(shí)這個(gè)進(jìn)程的狀態(tài)就是阻塞狀態(tài),表示當(dāng)前進(jìn)程不能直接被CPU調(diào)度,需要等待某種硬件資源的就緒。(值得注意的是,和CPU運(yùn)行隊(duì)列相同,操作系統(tǒng)操作的依舊是進(jìn)程對(duì)應(yīng)的PCB(task_struct結(jié)構(gòu)體對(duì)象),將PCB放到硬件的結(jié)構(gòu)體內(nèi)部的等待隊(duì)列中)。
10.
當(dāng)進(jìn)程訪問的硬件就緒之后,表示進(jìn)程又可以運(yùn)行了,這個(gè)時(shí)候,操作系統(tǒng)就又把該進(jìn)程對(duì)應(yīng)的PCB中的狀態(tài)改為R,然后將PCB放到CPU的運(yùn)行隊(duì)列里面,此時(shí)這個(gè)進(jìn)程的狀態(tài)就從阻塞狀態(tài)改為運(yùn)行狀態(tài)了。
11.
所謂的進(jìn)程的不同的狀態(tài),本質(zhì)上其實(shí)就是進(jìn)程在不同的隊(duì)列中,等待某種資源。
在CPU的運(yùn)行隊(duì)列中的進(jìn)程一般稱為R(運(yùn)行)狀態(tài)進(jìn)程,在硬件所對(duì)應(yīng)的內(nèi)存中的結(jié)構(gòu)體描述里面的阻塞隊(duì)列里的進(jìn)程,稱之為阻塞狀態(tài)進(jìn)程。
12.
當(dāng)多個(gè)進(jìn)程的狀態(tài)是阻塞的時(shí)候,這些進(jìn)程都無(wú)法被立即調(diào)度,也就是無(wú)法被CPU立即執(zhí)行,并且排隊(duì)的進(jìn)程其實(shí)是要等待很長(zhǎng)的時(shí)間的,因?yàn)橥庠O(shè)的速度和CPU的速度相比簡(jiǎn)直是太慢了,差的不是一星半點(diǎn)兒,這個(gè)時(shí)候,PCB和其對(duì)應(yīng)的進(jìn)程的代碼和數(shù)據(jù)就會(huì)占用內(nèi)存,這些進(jìn)程短期內(nèi)不會(huì)使用,還白白的占用著內(nèi)存空間,所以操作系統(tǒng)就把這些進(jìn)程的代碼和數(shù)據(jù)暫時(shí)保存到磁盤上,但進(jìn)程對(duì)應(yīng)的PCB還留在內(nèi)存里面,操作系統(tǒng)這樣的作法就可以節(jié)省內(nèi)存空間。
13.
我們將代碼和數(shù)據(jù)換出到磁盤的這種進(jìn)程,稱之為掛起進(jìn)程,該進(jìn)程的內(nèi)核數(shù)據(jù)結(jié)構(gòu)依舊在內(nèi)存,它的代碼和數(shù)據(jù)被操作系統(tǒng)暫時(shí)換出到磁盤里面,以節(jié)省內(nèi)存空間給其他需要加載到內(nèi)存的程序使用。
14.
等到進(jìn)程對(duì)應(yīng)的硬件資源就緒之后,操作系統(tǒng)再將進(jìn)程的代碼和數(shù)據(jù)換入到內(nèi)存當(dāng)中,當(dāng)進(jìn)程占用硬件資源結(jié)束后,操作系統(tǒng)再將PCB放入CPU的運(yùn)行隊(duì)列里面,使進(jìn)程重新運(yùn)行起來。
我們將進(jìn)程的代碼和數(shù)據(jù),加載到內(nèi)存和暫時(shí)保存到磁盤,稱為內(nèi)存數(shù)據(jù)的換入換出。
15.
阻塞不一定是掛起,但掛起一定是阻塞。
如果內(nèi)存空間特別夠的話,操作系統(tǒng)沒有必要將阻塞的進(jìn)程掛起。
2.具體的操作系統(tǒng):Linux下的進(jìn)程狀態(tài)
2.1 vim批量化注釋
批量化注釋: ctrl+v進(jìn)入塊選擇模式,kj上下移動(dòng)光標(biāo)選擇你要注釋的行,按下大寫的I并輸入注釋符號(hào)//,輸入完畢按下esc退出即可,vim會(huì)自動(dòng)在你選擇的行首前面加上注釋符號(hào)。
取消注釋: ctrl+v進(jìn)入塊選擇模式,利用hjkl選擇兩列的//注釋符號(hào),因?yàn)?/是兩列,最后按下d刪除即可取消注釋。
2.2 運(yùn)行狀態(tài)+休眠狀態(tài)(阻塞狀態(tài)的一種,是否掛起未知,這完全取決于OS,不同的OS不一定將掛起暴露出來給你)
下面的代碼其實(shí)是仿造的一種計(jì)算密集型進(jìn)程,演示進(jìn)程的R狀態(tài)。
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main()
6 {
7
8 while(1)
9 {}
10
11 }
1.
當(dāng)程序代碼僅僅只是一個(gè)死循環(huán)時(shí),我們將程序運(yùn)行起來,然后查看進(jìn)程狀態(tài),可以很明顯的看到狀態(tài)是R,也就是運(yùn)行狀態(tài)。
下面的代碼其實(shí)是仿造的一種IO密集型進(jìn)程,演示進(jìn)程的S狀態(tài)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4
5 int main()
6 {
7 int cnt=0;
8 int a=0;
9 while(1)
10 {
11 a=1+1;
12 printf("a的值是:%d,running flag=%d\n",a,cnt);
13 sleep(1);
14 }
15 }
2.
在代碼中添加printf語(yǔ)句之后,程序還在運(yùn)行,但進(jìn)程的狀態(tài)是S休眠狀態(tài),這是為什么呢?
因?yàn)槲覀兊拇a中訪問了顯示器,顯示器是外設(shè),速度非常慢,CPU會(huì)飛速的運(yùn)行完進(jìn)程的所有代碼,但是我們寫的進(jìn)程需要占用硬件資源,每一次占用硬件資源都要等顯示器就緒,這會(huì)花很長(zhǎng)的時(shí)間(和CPU相比),大概率99%的時(shí)間是進(jìn)程在等顯示器就緒,也就是在等IO就緒,1%的時(shí)間是CPU在運(yùn)行進(jìn)程的代碼,所以我們?cè)诓榭催M(jìn)程狀態(tài)的時(shí)候,極大概率上查到的都是S休眠狀態(tài)。更形象化的說明就是,在進(jìn)程訪問完畢一次顯示器的時(shí)候,CPU已經(jīng)將這個(gè)死循環(huán)代碼執(zhí)行了50、60萬(wàn)次,所以我們?cè)诓榭催M(jìn)程狀態(tài)的時(shí)候,進(jìn)程都是在等IO就緒的,所以就會(huì)查看到進(jìn)程是休眠狀態(tài),這也是阻塞狀態(tài)的一種。
3.
CPU計(jì)算的速度和IO的速度差別大概是幾十萬(wàn)倍。
4.操作系統(tǒng)不會(huì)讓你看到掛起狀態(tài),因?yàn)檫@對(duì)你來說毫無(wú)意義,操作系統(tǒng)不需要告訴你,你也不需要知道。
2.3 停止?fàn)顟B(tài)(stopped:阻塞狀態(tài)的一種,是否掛起未知,這完全取決于OS,不同的OS不一定將掛起暴露出來給你)
1.
當(dāng)進(jìn)程被停止的時(shí)候,其實(shí)也是阻塞狀態(tài)的一種,因?yàn)楫?dāng)前沒有代碼再運(yùn)行了。
這個(gè)進(jìn)程當(dāng)然也可以被掛起,但這一點(diǎn)是未知的,這完全取決于OS。
kill -19 + 進(jìn)程id --- 停止運(yùn)行進(jìn)程
kill -18 + 進(jìn)程id --- 繼續(xù)運(yùn)行進(jìn)程
2.狀態(tài)后面帶+,表示前臺(tái)進(jìn)程,狀態(tài)后面不帶+,表示后臺(tái)進(jìn)程。
3.
前臺(tái)進(jìn)程在運(yùn)行的時(shí)候,shell命令行無(wú)法繼續(xù)獲取命令行解析,但是可以通過ctrl+c將進(jìn)程終止掉。
后臺(tái)程序在運(yùn)行的時(shí)候,shell命令行可以繼續(xù)獲取命令行解析,但無(wú)法通過ctrl+c將進(jìn)程終止掉,需要通過kill指令 + -9信號(hào)才可以將進(jìn)程終止掉,也就是殺掉進(jìn)程。
下面是運(yùn)行狀態(tài)的前臺(tái)和后臺(tái)進(jìn)程
下面是休眠狀態(tài)的前臺(tái)和后臺(tái)進(jìn)程
2.4 磁盤休眠狀態(tài)(disk sleep:阻塞狀態(tài)的一種,高IO的環(huán)境可能出現(xiàn)這樣的狀態(tài)。同樣掛起是未知的,這完全取決于OS,不同的OS不一定將掛起暴露出來給你)
1.
S狀態(tài)是淺度睡眠狀態(tài),是可以被終止的,通過ctrl+c或kill -9 pid兩種方式進(jìn)行分別進(jìn)行前后臺(tái)終止。
2.
阻塞進(jìn)程過多時(shí),操作系統(tǒng)會(huì)將一些進(jìn)程掛起,以此來解決內(nèi)存空間不足的問題,如果掛起依舊無(wú)法解決內(nèi)存空間不足,Linux就會(huì)將進(jìn)程殺死,但是一旦殺死進(jìn)程很有可能導(dǎo)致進(jìn)程對(duì)應(yīng)的IO過程失敗,從而丟失大量數(shù)據(jù),這會(huì)對(duì)用戶造成巨大的損失,所以就出現(xiàn)了一個(gè)新的進(jìn)程狀態(tài),深度睡眠狀態(tài),這樣的進(jìn)程無(wú)法被OS殺掉,一般情況下,只能等待IO過程結(jié)束,讓進(jìn)程自己醒來,重新投入CPU的運(yùn)行隊(duì)列,重新繼續(xù)運(yùn)行進(jìn)程。萬(wàn)不得已可以通過斷電的方式來殺掉深度睡眠的進(jìn)程!??!
3.
D狀態(tài)是深度睡眠狀態(tài),在該狀態(tài)的進(jìn)程無(wú)法被OS殺掉?。?!只能通過斷電或者進(jìn)程自己醒來,來解決!
4.
當(dāng)然深度睡眠的狀態(tài)一般不會(huì)出現(xiàn),只有高IO的情況下,運(yùn)行某個(gè)程序時(shí),進(jìn)程才有可能出現(xiàn)深度睡眠的狀態(tài)。
5.
如果想要查看該進(jìn)程狀態(tài),可以了解dd指令,它可以營(yíng)造高IO的狀態(tài),這樣的狀態(tài)下運(yùn)行的進(jìn)程有可能會(huì)出現(xiàn)深度睡眠狀態(tài),也就是D狀態(tài)。dd指令詳解(轉(zhuǎn)載自csdn博主遠(yuǎn)近長(zhǎng)安博主的文章)
2.5 跟蹤狀態(tài)(tracing stop:阻塞狀態(tài)的一種,是否掛起未知,這完全取決于OS,不同的OS不一定將掛起暴露出來給你)
Makefile文件內(nèi)容:
1 myprocess:myprocess.c
2 gcc -o $@ $^ -g
3 .PHONY:clean
4 clean:
5 rm -f myprocess
$@代表冒號(hào)左側(cè)的目標(biāo)文件,$^代表冒號(hào)右側(cè)的依賴文件列表,這些是makefile中的特殊符號(hào)
1.
我們?cè)谡{(diào)試某個(gè)二進(jìn)制程序的時(shí)候,其實(shí)就是在調(diào)試該進(jìn)程,當(dāng)進(jìn)程中有斷點(diǎn)的時(shí)候,gdb中按下r進(jìn)行調(diào)試運(yùn)行,此時(shí)就會(huì)由于斷點(diǎn)的存在而停下來,這其實(shí)表示的就是我們當(dāng)前運(yùn)行的進(jìn)程停下來了,等待我們查看當(dāng)前進(jìn)程的上下文數(shù)據(jù),這就是tracing stop狀態(tài),跟蹤狀態(tài)。
2.
Linux內(nèi)核源代碼中跟蹤狀態(tài)用的還是T表示,這里為了區(qū)分跟蹤和停止?fàn)顟B(tài),將T改為t
2.6 僵死狀態(tài)(zombie:進(jìn)程退出狀態(tài)未被讀取,PCB依舊占用內(nèi)存資源,進(jìn)程資源未被回收干凈)
1.
進(jìn)程被創(chuàng)建的目的其實(shí)是為了完成某個(gè)任務(wù),這個(gè)任務(wù)是OS或用戶布置的,這也正是進(jìn)程對(duì)應(yīng)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)叫做task_struct的原因。
2.
當(dāng)進(jìn)程完成任務(wù)之后,父進(jìn)程或者OS一定得知道這個(gè)任務(wù)完成的結(jié)果是怎么樣的,所以在進(jìn)程終止的時(shí)候,OS機(jī)制是不可以立即釋放該進(jìn)程占用的內(nèi)存資源的,必須保存一段時(shí)間,讓父進(jìn)程或者OS來讀取進(jìn)程的結(jié)果。
3.
進(jìn)程退出的信息一般都會(huì)在其對(duì)應(yīng)的PCB中保存一段時(shí)間,等待父進(jìn)程或者OS讀取。
4.只要某個(gè)進(jìn)程退出,但是沒有被父進(jìn)程或者OS回收,這樣的進(jìn)程我們就稱之為僵尸進(jìn)程。
5.我們可以創(chuàng)建一個(gè)子進(jìn)程,讓父進(jìn)程不要退出,而且什么都不做一直運(yùn)行就好,不要回收子進(jìn)程,然后再讓子進(jìn)程正常退出,此時(shí)這個(gè)子進(jìn)程就會(huì)處于一個(gè)僵死狀態(tài),因?yàn)檫M(jìn)程退出后沒有人回收它。
下面是演示僵尸進(jìn)程的代碼
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int main()
6 {
7
8 pid_t id = fork();
9
10 if (id==0)
11 {
12 printf("I am a child process,pid:%d,ppid:%d\n",getpid(),getppid());
13 sleep(5);
14 exit(1);
15 }
16 else
17 {
18 while(1)
19 {
20 printf("I am a parent process,pid:%d,ppid:%d\n",getpid(),getppid());
21 sleep(1);
22 }
23 }
24 return 0;
25 }
一個(gè)可以每次間隔一秒查看進(jìn)程狀態(tài)的腳本
while :; do ps axj | head -1 && ps axj | grep myprocess | grep -v grep ; sleep 1 ; done
6.
父進(jìn)程處于淺度睡眠狀態(tài),因?yàn)橐蕊@示器就緒,這個(gè)我們前面說過,但子進(jìn)程處于Z狀態(tài),就是僵死狀態(tài),表示這個(gè)進(jìn)程已經(jīng)退出但是沒有人回收它,并且它的COMMAND后面加了defunct,這個(gè)單詞的意思是失效的,不起作用的。
7.
在結(jié)束進(jìn)程之后,操作系統(tǒng)會(huì)幫我們將父進(jìn)程和子進(jìn)程一起回收掉。以免內(nèi)存泄露的發(fā)生。
8.
進(jìn)程的退出狀態(tài)也屬于進(jìn)程的基本信息,也是需要數(shù)據(jù)進(jìn)行維護(hù)的,所以這種信息會(huì)被保存在進(jìn)程對(duì)應(yīng)的PCB里面,如果進(jìn)程的狀態(tài)一直是Z狀態(tài)的話(父進(jìn)程一直不讀取子進(jìn)程的退出狀態(tài)),那么PCB就需要一直維護(hù)這種狀態(tài)信息,雖然子進(jìn)程對(duì)應(yīng)的代碼和數(shù)據(jù)會(huì)被釋放,但是PCB是不會(huì)被釋放的,因?yàn)樗枰S護(hù)進(jìn)程的Z狀態(tài),所以這個(gè)時(shí)候就會(huì)產(chǎn)生內(nèi)存泄露的問題。
9.僵尸進(jìn)程無(wú)法被殺掉,即使通過kill和-9信號(hào)也無(wú)法殺掉,因?yàn)樗呀?jīng)死亡了,所以無(wú)法被殺掉的進(jìn)程有三個(gè),深度睡眠進(jìn)程,僵尸進(jìn)程,死亡進(jìn)程,D狀態(tài)是不能殺,Z和X是無(wú)法殺,因?yàn)橐呀?jīng)死了!??!
下面是另一種演示僵尸進(jìn)程的gif動(dòng)圖,手動(dòng)殺掉子進(jìn)程,但父進(jìn)程依舊運(yùn)行,不回收
2.7 死亡狀態(tài)(dead:Z狀態(tài)之后就是X狀態(tài),PCB也已被釋放)
1.
當(dāng)進(jìn)程死亡后,操作系統(tǒng)會(huì)立即回收進(jìn)程的所有資源和數(shù)據(jù),因?yàn)檫@個(gè)過程是非??斓模晕覀儫o(wú)法觀察到進(jìn)程的X狀態(tài),但這個(gè)概念比較好理解,簡(jiǎn)單來說其實(shí)就是進(jìn)程被終止掉了,它的PCB和對(duì)應(yīng)代碼和數(shù)據(jù)都退出內(nèi)存,不再占用內(nèi)存資源,此時(shí)這個(gè)進(jìn)程就是實(shí)實(shí)在在的死亡狀態(tài),它的所有資源都被操作系統(tǒng)釋放掉了。
2.8 孤兒進(jìn)程(沒爹的孩子,OS來當(dāng)這個(gè)爹?。。。?/h4>
1.
子進(jìn)程先退出,父進(jìn)程不退出繼續(xù)運(yùn)行且不回收子進(jìn)程,那么這個(gè)子進(jìn)程就是僵尸進(jìn)程,但如果父進(jìn)程先退出,那么子進(jìn)程就變成孤兒進(jìn)程,它會(huì)被1號(hào)進(jìn)程回收,1號(hào)進(jìn)程另一個(gè)叫法是init進(jìn)程,init進(jìn)程會(huì)回收孤兒進(jìn)程剩余資源。
2.
在僵尸進(jìn)程的最后部分,我們手動(dòng)殺掉了子進(jìn)程,子進(jìn)程就進(jìn)入了僵尸狀態(tài),這里我們手動(dòng)殺掉了父進(jìn)程,但父進(jìn)程卻沒有進(jìn)入僵尸狀態(tài),而是直接進(jìn)入死亡狀態(tài),只不過我們看不到死亡狀態(tài),這是為什么呢?其實(shí)是因?yàn)?strong>bash回收了父進(jìn)程的所有資源(PCB+代碼和數(shù)據(jù)),所以父進(jìn)程沒有變?yōu)榻┦M(jìn)程
3.
通過進(jìn)程狀態(tài)的查看,發(fā)現(xiàn)子進(jìn)程的父進(jìn)程變?yōu)?號(hào)進(jìn)程,我們稱被1號(hào)進(jìn)程領(lǐng)養(yǎng)的子進(jìn)程為孤兒進(jìn)程,1號(hào)進(jìn)程其實(shí)就是操作系統(tǒng),所以實(shí)際上子進(jìn)程是被操作系統(tǒng)領(lǐng)養(yǎng)。
4.
如果不領(lǐng)養(yǎng),那在子進(jìn)程退出的時(shí)候,子進(jìn)程就會(huì)變?yōu)榻┦M(jìn)程,此時(shí)就沒有人可以回收子進(jìn)程了,就會(huì)造成內(nèi)存泄露,所以操作系統(tǒng)為了管理好這些軟件資源,必須領(lǐng)養(yǎng)這個(gè)沒爹的孩子?。。?/strong>
5.
前臺(tái)進(jìn)程創(chuàng)建的子進(jìn)程如果變?yōu)楣聝哼M(jìn)程,那么這個(gè)進(jìn)程會(huì)自動(dòng)被切換為后臺(tái)進(jìn)程
五、進(jìn)程優(yōu)先級(jí)(受nice值調(diào)控的priority值 )
1.什么是優(yōu)先級(jí)?
1.先還是后獲得某種資源的能力,被稱之為優(yōu)先級(jí)。
2.先獲得就是優(yōu)先級(jí)高,后獲得就是優(yōu)先級(jí)低
2.為什么會(huì)存在優(yōu)先級(jí)?
1.
因?yàn)橘Y源是有限的。
2.
比如現(xiàn)在有20多個(gè)進(jìn)程要訪問CPU,但CPU只有一個(gè),另外20個(gè)進(jìn)程要訪問網(wǎng)卡,另外40個(gè)進(jìn)程要訪問磁盤,但是資源太少了,但訪問的又太多了,此時(shí)就會(huì)出現(xiàn)優(yōu)先級(jí)的情況。想要訪問,可以!但需要排隊(duì),這就出現(xiàn)了優(yōu)先級(jí)。
3.Linux優(yōu)先級(jí)特點(diǎn)
1.
進(jìn)程的優(yōu)先級(jí)和狀態(tài)一樣,本質(zhì)都是PCB里面的一個(gè)數(shù)字(也可能是多個(gè)數(shù)字),操作系統(tǒng)通過這些數(shù)字來辨別進(jìn)程的狀態(tài)和優(yōu)先級(jí)。
2.
通過ps -al指令可以查看到進(jìn)程的詳細(xì)信息,PRI和NI的值合并在一起代表Linux進(jìn)程的優(yōu)先級(jí)。PRI其實(shí)就是最終優(yōu)先級(jí),只不過它受NI值的調(diào)控。
4.修改Linux下的優(yōu)先級(jí)(top指令 + root身份)
1.
最終優(yōu)先級(jí)=老的優(yōu)先級(jí)(固定為80)+nice值,Linux支持進(jìn)程在運(yùn)行中,通過修改nice值的改變來進(jìn)行進(jìn)程優(yōu)先級(jí)的調(diào)整。
2.
PRI的值越小代表優(yōu)先級(jí)越高,輸入sudo top指令(用管理員的身份去做),然后按下r,輸入對(duì)應(yīng)的進(jìn)程pid(表示你要修改哪個(gè)進(jìn)程的優(yōu)先級(jí)),然后輸入整數(shù)值,這個(gè)值就是你要修改的nice值。
3.
優(yōu)先級(jí)過度設(shè)置,會(huì)導(dǎo)致CPU調(diào)度失衡,所以nice值是有范圍的,不能讓你隨意過度的調(diào)整,nice值的范圍是-20到19,一共40個(gè)優(yōu)先級(jí)級(jí)別,所以最終優(yōu)先級(jí)的范圍就是60到99
4.
下面是nice值分別調(diào)整為-100和100后,進(jìn)程的優(yōu)先級(jí)分別為60和99的結(jié)果,這也就說明,OS不會(huì)讓我們過度隨意調(diào)整nice值,nice值的調(diào)整是有一個(gè)限度范圍的。
六、四個(gè)補(bǔ)充的進(jìn)程概念(注意區(qū)分并行和并發(fā))
競(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í),值得注意的是進(jìn)程排隊(duì)的時(shí)候,OS操作的是進(jìn)程對(duì)應(yīng)的PCB而不是進(jìn)程對(duì)應(yīng)的代碼和數(shù)據(jù)。
獨(dú)立性: 多進(jìn)程運(yùn)行,需要獨(dú)享各種資源,多進(jìn)程運(yùn)行期間互不干擾!就算是父子進(jìn)程在運(yùn)行時(shí)也是互不干擾的。例如下面的子進(jìn)程掛掉,變?yōu)榻┦M(jìn)程,但父進(jìn)程依舊可以運(yùn)行,所以進(jìn)程間運(yùn)行是互不干擾的。
并行: 多個(gè)進(jìn)程在多個(gè)CPU下分別,同時(shí)進(jìn)行運(yùn)行,這稱之為并行。有幾個(gè)CPU,就可以同時(shí)運(yùn)行幾個(gè)進(jìn)程。
并發(fā): 多個(gè)進(jìn)程在一個(gè)CPU下采用進(jìn)程切換的方式來實(shí)現(xiàn)多個(gè)進(jìn)程的運(yùn)行(不是同時(shí)運(yùn)行),在一個(gè)時(shí)間段內(nèi),讓多個(gè)進(jìn)程都得以推進(jìn),稱之為并發(fā)。
如果只有一個(gè)CPU,那么在任何時(shí)刻,只能有一個(gè)進(jìn)程正在運(yùn)行!多個(gè)進(jìn)程的運(yùn)行依靠的是進(jìn)程切換,呈現(xiàn)給使用者的就是我們好像看到多個(gè)進(jìn)程在同時(shí)運(yùn)行,但其實(shí)不是這樣的,任何時(shí)刻只能有一個(gè)進(jìn)程在運(yùn)行。
不是一個(gè)進(jìn)程必須在CPU上跑完才能被CPU拿下來,當(dāng)代計(jì)算機(jī)采用的是時(shí)間片輪轉(zhuǎn)的策略,一個(gè)進(jìn)程可以跑一會(huì)兒就換到下一個(gè)進(jìn)程,在一個(gè)時(shí)間段內(nèi),每個(gè)進(jìn)程都可以跑多次,呈現(xiàn)出來的現(xiàn)象就是多個(gè)進(jìn)程同時(shí)運(yùn)行,例如我的計(jì)算機(jī)現(xiàn)在可以打開畫圖工具,還可以開直播和別人聊天,還可以打開xshell進(jìn)行l(wèi)inux的學(xué)習(xí),但這些進(jìn)程并不是同時(shí)在一個(gè)CPU下運(yùn)行的,只是采用了進(jìn)程切換的方式來完成的。
CPU可以在幾毫秒的時(shí)間內(nèi),就將每個(gè)進(jìn)程都運(yùn)行好幾次,CPU讀取代碼的速度非???!
時(shí)間片輪轉(zhuǎn)(百度百科)
七、進(jìn)程切換(進(jìn)程的上下文保護(hù)和恢復(fù))
1.
一個(gè)CPU會(huì)有大量的寄存器,雖然寄存器很多,但是只有一套寄存器,寄存器分為用戶可見的寄存器和用戶不可見的寄存器(狀態(tài)寄存器、權(quán)限寄存器等),對(duì)于寄存器的深入了解,可以看看寄存器詳談(轉(zhuǎn)載自知乎博主軒轅之風(fēng)的文章)
2.
CPU永遠(yuǎn)做三件事情,取指令(代碼被編譯器翻譯成二進(jìn)制指令),分析指令,執(zhí)行指令,在CPU中有一個(gè)叫做eip的寄存器,專門用來標(biāo)識(shí)下一次應(yīng)該從當(dāng)前進(jìn)程的具體的位置讀取相應(yīng)的代碼和指令
3.
當(dāng)進(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ù)是兩碼事。
4.
進(jìn)程在運(yùn)行的時(shí)候,的確是占有CPU的,但進(jìn)程并不是一直占有CPU直到進(jìn)程運(yùn)行結(jié)束,這個(gè)我們前面說過,計(jì)算機(jī)有時(shí)間片輪轉(zhuǎn)的策略,每一個(gè)進(jìn)程在運(yùn)行的時(shí)候,都有自己的時(shí)間片,所以在進(jìn)程重新被CPU調(diào)度的時(shí)候,CPU必須知道上一次這個(gè)進(jìn)程運(yùn)行到什么時(shí)候了,當(dāng)進(jìn)程被換下去的時(shí)候,進(jìn)程的運(yùn)行信息會(huì)被存在操作系統(tǒng)里面(具體什么位置這里不詳談),以便下次CPU重新調(diào)度時(shí)進(jìn)程能夠正常運(yùn)行,這叫做進(jìn)程的上下文保護(hù)。當(dāng)進(jìn)程被CPU重新調(diào)度上來時(shí),首先要做的第一件事情就是讀取操作系統(tǒng)中進(jìn)程運(yùn)行的相關(guān)數(shù)據(jù),這叫做進(jìn)程的上下文恢復(fù)。
5.
在任何時(shí)刻,CPU中的寄存器雖然被所有進(jìn)程共享,但寄存器內(nèi)的數(shù)據(jù)是每個(gè)進(jìn)程私有的,這些寄存器內(nèi)的數(shù)據(jù)就是進(jìn)程的上下文數(shù)據(jù),這些寄存器內(nèi)的數(shù)據(jù)是時(shí)刻在不斷變化的,OS會(huì)實(shí)時(shí)加載當(dāng)前運(yùn)行進(jìn)程的上下文數(shù)據(jù)到寄存器里面。文章來源:http://www.zghlxwxcb.cn/news/detail-824140.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-824140.html
到了這里,關(guān)于【Linux】Linux進(jìn)程的理解 --- 馮諾依曼體系、進(jìn)程描述符、狀態(tài)、優(yōu)先級(jí)、切換…的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!