前言:
? ? ? ? 上文我們講到了操作系統與Linux中進程的狀態【Linux】進程狀態-CSDN博客
? ? ? ? 本文我們來講進程的優先級、以及進程的切換
進程優先級
什么是優先級??
? ? ? ? CPU中資源是有限的,而進程的數量一定是遠大于CPU資源的,所以優先級是進程得到CPU資源的先后順序。優先級也是進程的屬性之一,保存在PCB中。
優先級的實現
優先級是進程的屬性之一,保存在PCB中。
? ? ? ? 優先級中PCB中用整型表示,其值越小表示優先級越高,反之優先級越低。
? ? ? ? 優先級是可以被修改的。但考慮到時間片的分時操作系統,以及公平性,優先級不能出現大幅度的修改。
? ? ? ? 如上圖,我在Linux中使用執行查看當前正在運行的進程信息。可以看到紅圈這兩個值:
? ? ? ? PRI:表示進程的優先級,其默認值是80
? ? ? ? NI:表示進程優先級的修正數據,稱為nice值
? ? ? ? 優先級的修改:是通過nice值的修改實現的,既最終的優先級 = PRI + NI
? ? ? ? 如圖,通過renice指令來修改進程的優先級后,我們再次查看進程信息可以發現第一個被修改的進程NI變成了10。最終的優先級變成了90。?說明默認值是不改變的,優先級修改是通過nice值的修改而實現的
? ? ? ?
補充:UID
? ? ? ? 如上圖,我們可以看到第三列有一個叫做UID的。那什么是UID呢?
? ? ? ? UID:user id,表示用戶標識符?
? ? ? ? 在linux中任何訪問資源的操作都是進程實現的,進程代表當前的用戶。那系統是如何判斷當前進程訪問的權限的呢?
? ? ? ? 其實就是通過UID實現的:通過進程中的UID與文件的UID相比較,就可以判斷出這個進程的訪問權限是擁有者、所屬組還是other。
優先級的極值
? ? ? ? 如圖可知,優先級的范圍是[60 - 99],而nice值的范圍是[-20 - 19]
? ? ? ? 優先級范圍設置的并不寬泛,因為優先級范圍設置過大會導致,優先級低的進程長時間不能獲得CPU資源,進而導致:進程饑餓。
?
進程關系
競爭性:進程與進程之間是存在競爭關系的。CPU資源有限,為獲得CPU資源,為了高效完成任務,更合理的競爭相關資源,便有了優先級。
獨立性:多進程運行時,各個進程之間是獨享資源的,互不干擾。
并行:多個進程在多個CPU下,同時運行。
并發:多個進程在一個CPU下不停的切換運行,在一段時間內,讓多個進程不斷推進。
進程切換
????????進程的切換討論范圍在長代碼與死循環代碼,因為較短的代碼一瞬間就執行完畢了,沒有切換這一說法
死循環進程
? ? ? ? 死循環進程一段占用CPU執行代碼,會一直占用CPU嗎?
? ? ? ? 并不會,因為在計算機是分時操作系統,在進程執行的過程中存在“時間片”。每個進程都有其適合的“時間片”(本質其實就是計數器),時間片達到時,進程就會從CPU上剝離下來。
? ? ? ? 所以死循環并不會一直占用CPU。
CPU中的寄存器
? ? ? ? CPU中存在各種各樣的寄存器,用于保存當前正在運行進程的各種臨時數據
? ? ? ? 寄存器就是CPU內部的臨時空間
? ? ? ? 寄存器!=寄存器中的數據
如何切換
? ? ? ? A進程占用CPU執行完一個時間片后,要被剝離CPU,進而執行下一個進程。
? ? ? ? 那么當再次執行A進程時,應該從上次執行位置開始繼續向下執行。?這就意味著剝離時,需要當前進程把自己的上下文記錄下來,以便于下一次繼續執行。
? ? ? ? 進程上下文保存到了哪里呢?保存到了進程task_struct的TSS中(TSS:任務狀態段),下一次執行時,之間覆蓋CPU中的寄存器內容即可。
? ? ? ? 對于以及執行過的進程才需要記錄上下文,對于之前還沒有執行過的繼承無需記錄,及其將寄存器內容初始化即可。
Linux中真實的調度算法:O(1)調度算法
? ? ? ? 如上圖,runqueue是一個運行隊列,且一個CPU只有一個運行隊列。
queue[140]
????????我們先來介紹一下queue[140]:它的數據類型是 struct task_struct*
struct task_struct* queue[140]
? ? ? ? queue一共有140個元素,一個元素就是一個進程隊列,其下標映射了優先級。前100個元素代表實時優先級(我們不關心)后40個代表我們上面所講的普通優先級。
? ? ? ? 我們之前講到優先級的范圍是:60~99,那對應在queue中的下標表示就是:100~139(x - 60 +100)。比如優先級為64的進程就會鏈接至下標為104的節點下,多個優先級一樣的進程都會被依次鏈接在同一個進程隊列中。
bitmap
? ? ? ? bitmap[5]用于在queue中快速查找進程。
? ? ? ? bitmap的數據類型是 unsigned int,一個元素有32bit,一個有5個這樣的元素。
? ? ? ? 用bit位記錄進程信息,0表示沒有進程,1表示有進程。從下標0開查詢,一次性查詢32個位置,并從最后一個“1”開始調用進程(既優先級最高的進程位置)。
nr_active
? ? ? ? 記錄進程的個數,當進程個數為0時,不在使用bitmap查詢進程。
過期隊列與活躍隊列
? ? ? ? 在圖中我們可以看到有兩個一模一樣的隊列結構(藍框與紅框),并由兩個指針分別指向:active(活躍)、expired(過期)。
? ? ? ? active指向的隊列叫做活躍隊列,反之另一個叫過期隊列。
? ? ? ? 活躍隊列上的進程是要占用CPU資源,執行代碼的。當活躍隊列上的進程執行完一個時間片后,會放到過期隊列中的相應位置上(優先級對應的位置)。當活躍隊列上的進程全部執行完時,active指針與expired指針交換:過期隊列再次變為活躍隊列,繼續執行之前的進程。
Linux中進程切換的整體過程
? ? ? ? 1.由bitmap在活躍隊列中查詢進程位置(優先級最高進程的位置)? ? ? ?
????????2.依次占用CPU資源,執行相關進程
? ? ? ? 3.時間片耗盡,記錄上下文后從CPU上剝離,并鏈接至過期隊列中
? ? ? ? 4.直到活躍隊列中沒有進程,指針交換,再次循環至第一步
補充:
? ? ? ? 如果新建了一個進程,是插入活躍隊列還是過期隊列?
? ? ? ? :活躍隊列,新創建的進程應該盡快獲得執行機會,而不是放入已經執行過的過期隊列中等待下一次的調度