linux 进程调度 运行队列 自旋锁,linux内核进程调度(自旋锁)
2.1首先讓我們了解,操作系統(tǒng)分為兩類:一類是實時操作系統(tǒng),一類是分時操作系統(tǒng)。它們的共同特點是都是多任務(wù)的?。多任務(wù)操作系統(tǒng)分為兩類:非搶占式多任務(wù)和搶占式多任務(wù)。
非搶占式多任務(wù),就是指進程不斷的占用CPU,直到運行完畢或者是自己讓出。這樣的系統(tǒng)實在不適合多任務(wù)操作系統(tǒng),畢竟,長期占用CPU對任何多任務(wù)系統(tǒng)來說,都是很容易讓系統(tǒng)崩潰的!這樣的操作系統(tǒng)也很少。
搶占式多任務(wù),就是進程占用CPU時間是有限的,到了一定時間,它必須讓出來,被后來的進程搶占。進程在被搶占之前的運行時間,我們把它叫做時間片。搶占式多任務(wù)調(diào)度是很多操作系統(tǒng)最基本的調(diào)度方法。
2.2那么,我們具體如何調(diào)度進程呢?我們發(fā)現(xiàn)進程間的不同之處:一些是I/O消耗型,就是說進程頻繁的和外界交互,比如要打開、瀏覽文件,要等待用戶命令,要讀取光盤上的數(shù)據(jù),等等。一些是處理器消耗型,就是說進程多數(shù)時間總是不斷的在CPU里面運行,很少需要等待。
所以,我們應(yīng)該區(qū)別對待這兩種類型的進程。我們利用處理器遵循的原則是:吞吐量大和響應(yīng)時間快。對于I/O消耗型,由于它需要頻繁等待I/O,這樣
它需要較高的優(yōu)先級來搶占當前運行進程,以確保當I/O條件滿足后能馬上得到CPU響應(yīng),并且它的時間片相對其它處理器消耗型進程來說更長。相反,處理器
消耗型進程優(yōu)先級相對就低了,并且其時間片沒有必要太長。
讓我們看一個例子,加深理解:假設(shè)用戶運行兩個程序,一個是打字程序,一個是視頻程序。很明顯,打字程序是I/O消耗型的,而視頻程序是處理器消耗
型的。人的打字速度再快也不可能快過計算機計算視頻編碼并在屏幕上顯示出來的速度,可是人希望他每打一個字,就能輸入計算機并在屏幕上顯示。因此,對于打
字程序,我們讓它有較高的優(yōu)先級,以便讓人可以馬上輸入,并且其時間片也要多些;相比下,視頻程序的優(yōu)先級就低些,以便讓位給打字程序,時間片當然也就少
些。
實際上,一般來說,優(yōu)先級越高,時間片也就越長,反之亦然。
2.3那么,具體如何設(shè)定優(yōu)先級和時間片呢?Linux有兩種策略:一是設(shè)置進程優(yōu)先級值nice,它的范圍從-20到19。nice值越低,優(yōu)先級別越高,默認下為0。還有一個實時優(yōu)先級策略,這個待會討論。
對于時間片,前面說了,優(yōu)先級越高,時間片也就越長。最小的時間片為10ms,最大為200ms,默認為100ms。
這里要強調(diào)的是,進程并不是一直都是一種類型的,而且,有些時候進程是哪種類型本來就不明顯。這樣linux必須動態(tài)的計算優(yōu)先級和時間片。對于優(yōu)先級,每次進程讓出CPU后都會更新;對于時間片,不是每次都必須耗盡。待會還會具體講這個問題。
2.4先放一放優(yōu)先級和時間片的問題。讓我們先討論CPU調(diào)度進程。其實很簡單,每一個CPU(單CPU當然也如此)都有一個可執(zhí)行隊列——
struct
runqueue,里面包括很多信息:自旋鎖lock、活動優(yōu)先級數(shù)組指針*active、超時優(yōu)先級數(shù)組指針*expired、優(yōu)先級數(shù)組array
[2]……等等。
2.5有必要討論下自旋鎖,當進程進入CPU運行時,就會給它的代碼上鎖,以免別的CPU中的進程修改里面的代碼(不排除CPU給別的CPU上鎖這
樣的情況,以后會討論到。)。所謂子旋鎖就是這樣的一把鎖:進程A進入CPU,鎖上門運行,進程B來到CPU前,發(fā)現(xiàn)門被鎖上了,于是等待進程A出來交出
開鎖鑰匙。
正如每次我們談到“鎖”這個概念時,總會談到“死鎖”——是的,我們用鎖,就必須防止死鎖,死鎖是這樣產(chǎn)生的:進程A進入CPU運行,上鎖,進程B
來到CPU門前等待進程A出來,可是糟糕的情況出現(xiàn)了:進程A要想出來就必須獲取進程B的幫助,于是進程A開始等待進程B的幫助,可是進程B卻又一直等待
進程A出來!這樣的等待無法終止,最終成為死鎖。
再比如,進程A要鎖上甲代碼段,然后想再去鎖乙代碼段,進程B要鎖上乙代碼段,然后想再去鎖甲代碼段。第一步大家都沒問題,可是兩個進程都要進行下
一步時,發(fā)現(xiàn)無法完成任務(wù)了:進程A已經(jīng)鎖上甲代碼段,進程B沒法再去操作它,同理進程B已經(jīng)鎖上乙代碼段,進程A也沒辦法操作它,于是兩個進程等待對方
釋放鎖,當然,這樣的等待也是無止無休的。這就好象兩輛汽車在一座很榨的橋上相向行駛,兩車碰頭誰也不讓誰,都在等待對方讓路。
避免死鎖,必須使每次上鎖操作都是有順序的、原子的操作。有順序的,也就是說每次都按照可執(zhí)行隊列地址從低向高的順序上鎖——我們以后會很好的討論這個。
原子的,就是說每次上鎖必須執(zhí)行到底,否則不予執(zhí)行!
關(guān)于鎖的問題,以后還會進一步討論。
2.6是時候討論活動優(yōu)先級數(shù)組指針*active、超時優(yōu)先級數(shù)組指針*expired和優(yōu)先級數(shù)組array[2]了。其實還是很簡單的。
每一個運行隊列都有兩個數(shù)組:一個當然是活躍的,另一個是過期的;所謂活躍的,就是里面的進程沒有使用完時間片,過期的,就是里面的進程時間片已經(jīng)用完了。active指向活躍的數(shù)組,expired則指向過期的數(shù)組。數(shù)組值最大默認為140。
在活躍數(shù)組中,如何確定哪個進程執(zhí)行呢?首先請看優(yōu)先級數(shù)組的定義:
struct prio_array{
int nr_ative;/*任務(wù)數(shù)組*/
unsigned bitmap[BITMAP_SIZE];/*優(yōu)先級位圖*/
struct list_head queue[MAX_PRIO];/*優(yōu)先級隊列*/
};
優(yōu)先級位圖bitmap[BITMAP_SIZE]為每一個優(yōu)先級準備一位,開始為0,當要求某優(yōu)先級進程執(zhí)行時,對應(yīng)的位置為1。比如要求優(yōu)先級為7的進程執(zhí)行,那么bitmap[BITMAP_SIZE]的第7被置為1。
2.7重新計算時間片。老版本的linux是這樣計算時間片的:當進程的時間片都使用完后,用for語句遍歷每一個進程,計算它們的時間片!!
天,這是非常低效率的,而且相當復(fù)雜!
新的linux很簡單,剛才提到活躍數(shù)組和過期數(shù)組——它們的用途就在這:活躍數(shù)組放著時間片還未用完的進程,過期數(shù)組放著時間片已經(jīng)用完的數(shù)組。當進程的時間片使用完后,就被轉(zhuǎn)入過期數(shù)組,同時,計算好它的新的時間片。
2.8計算優(yōu)先級和時間片。前面已經(jīng)說了,優(yōu)先級和時間片由進程的類型決定,但是我們可不能預(yù)知進程到底是什么類型的。linux采用靜態(tài)優(yōu)先級和動態(tài)優(yōu)先級的方法,準確的制定了進程的優(yōu)先級。
首先,進程獲得由用戶給定的靜態(tài)優(yōu)先級nice,這個值在-20到19之間,它不會被改變。接著,進程會運行,然后linux會判斷它的休眠時間來
決定動態(tài)優(yōu)先級。休眠時間長,說明是I/O消耗型;短,則是處理器消耗型。linux根據(jù)休眠長短,以nice為基數(shù),修正動態(tài)優(yōu)先級,也就是對進程的優(yōu)
先級進行最大加5的處罰或則最小-5的獎勵,例如,一個進程休眠時間長,說明是I/O消耗型,若靜態(tài)優(yōu)先級為7,這個時候獎勵它-5,使它獲得動態(tài)優(yōu)先級
為2;而一個進程休眠時間很短,說明是處理器消耗型,若靜態(tài)優(yōu)先級為2,這個時候處罰它+5,使它的動態(tài)優(yōu)先級為7。這樣,可以真正的、準確的計算出優(yōu)先
級。
優(yōu)先級計算出來,時間片也就不難了
總結(jié)
以上是生活随笔為你收集整理的linux 进程调度 运行队列 自旋锁,linux内核进程调度(自旋锁)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在ThinkAdmin中增加显示数据表格
- 下一篇: JMeter Linux下执行测试