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