Linux核心設計與實現第八周讀書筆記

2022-09-01 06:42:06 字數 4118 閱讀 5803

程序在作業系統看來是程式的執行態表現形式。

多工作業系統就是能同時併發地互動執行多個程序的作業系統。

多工作業系統會使多個程序處於堵塞或者睡眠狀態。這些任務儘管位於記憶體,但並不處於可執行狀態。相反,這些程序利用核心堵塞自己,直到某一事件發生。

多工系統可以劃分為兩類:非搶占式多工和搶占式多工。

o(1)排程程式

策略決定排程程式在何時讓什麼程式執行。

處理器消耗型:把時間大多用在執行**上。除非被搶占,否則他們通常都一直不停地執行。排程策略往往是盡量降低他們的排程頻率,而延長其執行時間。

排程策略通常要在兩個矛盾的目標中間尋找平衡:程序響應迅速(響應時間短)和最大系統利用率(高吞吐量)。

這是一種根據程序的價值和其對處理器時間的需求來對程序分級的想法。

排程程式總是選擇時間片未用盡而且優先順序最高的程序執行。

linux採用了兩種不同的優先順序範圍:

2、實時優先順序:其值是可配置的,預設情況下的變化範圍是0~99.越高的實時優先順序數值意味著程序優先順序越高。任何實時程序的優先順序都高於普通的程序。

任何實時程序的優先順序都高於普通程序,也就是說實時優先順序和nice優先順序處於互不相交的兩個範疇。

時間片過長會導致系統對互動的響應表現欠佳,太短會明顯增大程序切換帶來的處理器耗時。

程序所獲得的處理器時間其實是和系統負載密切相關。這個比例進一步還會受程序nice值的影響。

linux排程器是以模組方式提供的,這樣做的目的是允許不同型別的程序可以有針對性地選擇排程演算法。這種模組化結構被稱為排程器類。

每個排程器都有乙個優先順序,基礎的排程器**定義在kernel/sched.c檔案中,它會按照優先順序順序來遍歷排程類,擁有乙個可執行程序的最高優先順序的排程器類勝出,去選擇下面要執行的那乙個程式。

完全公平排程(cfs):針對普通程序的排程類,在linux中稱為sched_normal,cfs演算法定義在檔案kernel/sched_fair.c中。

cfs採用的方法是對時間片分配方式進行根本性的重新設計(就程序排程器而言);完全摒棄時間片而是分配給程序乙個處理器使用比重。

我們希望所有程序能只執行乙個非常短的週期,但是cfs充分考慮了這將帶來的額外消耗,實現中首先要確保系統效能不受損失。

cfs的做法是允許每個程序執行一段時間、迴圈輪轉、選擇執行最少的程序作為下乙個執行程序,而不再採用分配給每個程序時間片的做法。nice值在cfs中被作為程序獲得的處理器執行比的權重:越高的nice 值程序獲得更低的處理器使用權重。

為了計算準確的時間片,cfs為完美多工中的無限小排程週期的近似值設立了「目標延遲」,越小的排程週期將帶來越好的互動性,同時也更接近完美的多工。cfs引入每個程序獲得的時間片底線—最小粒度。預設情況下這個值是1ms。即便是可執行程序數量趨於無窮,每個最少也能獲得1ms的執行時間,確保切換消耗被限制在一定範圍內。

總結一下,任何程序獲得的處理器時間是由它自己和其他所有可執行程序nice值的相對差值決定的。nice值對時間片的作用不再是算術加權,而是幾何加權,任何nice值對應的絕對時間不再是乙個絕對值,而是處理器的使用比。

當每次系統時鐘節拍發生時,時間片都會被減少乙個節拍週期。當乙個程序的時間片被減少到0的時候,它就會被另乙個尚未減到0的時間片可執行程序搶占。

排程器實體結構作為乙個名為se的成員變數,嵌入在程序描述符struct task_struct內。

vruntime變數存放程序的虛擬執行時間,該執行時間的計算是經過了所有可執行程序總數的標準化。虛擬時間以ns為單位,所以和定時器街拍不再相關。cfs使用vruntime變數來記錄乙個程式到底執行了多長時間以及它還應該再執行多久。 

update_curr()計算了當前程序的執行時間,並且將其存放在變數delta_exec中。然後他把執行時間傳遞給__update_curr(),由後者再根據當前可執行程序總數對執行時間進行加權計算,最終將上述的權值與當前執行程序的vruntime相加。

update_curr()由系統定時器週期性呼叫。

當cfs需要選擇下乙個執行程序時,它會挑乙個具有最小vruntime值得程序。

cfs使用紅黑樹來組織可執行程序佇列,並利用其迅速找到最小vruntime值得程序。

cfs的程序選擇演算法可簡單總結為「執行rbtree樹中最左邊葉子節點所代表的那個程序。」實現這一過程的函式是__pick_next_entity()

發生在程序變為可執行狀態(被喚醒)或者通過fork()呼叫第一次建立程序時。enqueue_entity()函式實現了這一目的。                   

該函式更新執行時間和其他一些統計資料,然後呼叫__enqueue_entity()進行繁重的插入操作,把資料項真正插入到紅黑色樹中。

刪除動作發生在程序堵塞或者終止時。    

程序排程的主要入口點是函式schedule(),它正是核心其他部分用於呼叫程序排程器的入口:選擇哪個程序可以執行,何時將其投入執行。該函式中唯一重要的事情是,它會呼叫pick_next_task(),該函式會以優先順序為序,從高到低,依次檢查每乙個排程類,並且從最高優先順序的排程類中,選擇最高優先順序的程序。該函式的核心是for()迴圈,它以優先順序為序,從最高的優先順序類開始,遍歷了每乙個排程類。

休眠:程序把自己標記成休眠狀態,從可執行紅黑樹中移出,放入等待佇列,然後呼叫schedule()選擇和執行乙個其他程序。

喚醒:程序被置為可執行狀態,然後在從等待佇列中移到可執行紅黑樹中。

休眠有兩種相關的程序狀態:task_interruptibletask_uninterruptible。他們唯一的區別是task_uninterruptible的程序會忽略訊號,而task_interruptible狀態的程序如果接收到乙個訊號,會被提前喚醒並響應該訊號。兩種狀態的訊號位於同一等待佇列上,等待某些事件,不能夠執行。

程序通過執行下面幾個步驟將自己加入到乙個等待佇列中:

喚醒函式通過函式wake_up()進行,它會喚醒指定的等待佇列上的所有程序。它呼叫函式try_to_wake_up(),該函式負責將程序設定為task_running狀態,呼叫enqueue_task()將此程序放入紅黑樹中,如果被喚醒的程序優先順序比當前就正在執行的程序優先順序高,還要設定need_resched標誌。

由定義在kernel/sched.c中的context_switch()函式負責處理。每當乙個新的程序被選出來準備投入執行的時候,schedule()就會呼叫該函式。它完成了下面兩項基本工作:

使用者搶占在以下情況時產生:

只要沒有持有鎖,核心就可以進行搶占。

核心搶占會發生在:

linux提供了兩種實時排程策略:sched_fifosched_rr

演算法設計與分析第八周leetcode

longest valid parentheses difficulty hard total accepted 151.5k total submissions 629.9k given a string containing just the characters and find the le...

第八周 刪除

題目描述 從串s中刪除其值等於c的所有字元。如從message中刪除 e 得到的就是mssag 1 演算法庫中的標頭檔案部分 ifndef sqstring h included define sqstring h included define maxsize 100 最多的字元個數 typede...

第八周學習

第八周學習週報 2018.10.22 10.28 一 本週學習情況 本週主要學習了 開源硬體 arduino基礎教程 1 歐姆定律 2 光敏電阻與三極體的初步認識 3 多種方法控制並點亮led燈 按鈕開關,光敏開關,紅外開關 訪問了csdn社群的計算機基礎板塊,學習大神的帖子。利用開源硬體對網課裡的...