操作系統筆記-4-進程&線程調度

引言

當我們在平時工作或學習中用電腦的時候,我想很多人都是一邊聽着音樂一邊寫代碼、看文檔、編輯Markdown寫筆記或者Chrome看着網頁,不知道你有沒有好奇電腦爲什麼可以可以同時完成這些程序的運行,並且如果你細心可能發現了有時候程序的響應快,有時候響應慢。這些都是因爲進程&線程調度的結果,哪怕你的電腦處理器只有一核,可同時同時執行多個應用程序。

爲何需要調度

並不是所有的程序都是cpu密集型的,也有I/O密集型,如下圖,a是cpu密集型任務,它有很長的cpu週期,而b則持有cpu的時間短但是卻很頻繁。如果你是系統的設計者你會讓程序如果運行呢?如果每次都先執行完a再執行b,那麼磁盤可能長期處於空閒狀態,這裏有一個簡單的想法是,優先保證b進程執行,這樣磁盤就可以長期保持忙碌的狀態。所以,進程調度的目的一方面是讓程序併發執行,一方面是爲保持系統各個組件處於忙碌狀態避免資源浪費。
在這裏插入圖片描述
下面的筆記是探索進程&線程調度的筆記,一步步揭開處理器調度神祕的面紗。本文的結果,先介紹一些調度的基本概念方便理解後邊的內容,然後會介紹調度算法(以單核和進程爲視角介紹,線程和進程差不多的),之後會介紹線程調度的特有特徵,然後介紹多核心環境下調度,最後可能會簡單的舉個例子介紹實際OS採用的是什麼調度策略。

基本概念

調度器

調度器是操作系統實現的,通過一定的算法從一堆就緒線程中選擇一個,然後完成上下文切換,然後執行新調度線程的代碼的一個線程,注意調度器也是一個線程,它是一個高優先級的內核線程。

搶佔式與非搶佔式
  • 非搶佔式:挑選一個進程一直運行,直到進程阻塞(I/O或等待其他線程)或者自願讓出cpu
  • 搶佔式:挑選一個進程執行固定的時間,當進程用完最大時間還在執行時會被掛起,然後切換另一個就緒的進程,並且當一個比當前運行進程更高優先級進程到達時,可以搶佔當前進程的cpu
何時調度
  • 在創建新進程後,需要決策時運行父進程還是子進程
  • 在一個進程退出時
  • 當一個進程被阻塞在I/O、信號量或者其他原因阻塞時,必須選擇另一個進程運行
  • 在一個I/O中斷時
調度環境
  • 批處理:適合非搶佔式算法,減少進程切換
  • 交互式:搶佔是必須的,不能讓一個進程一直霸佔CPU
  • 實時:對deadline要求嚴格
調度算法的目標
  • 公平:相似的進程應得到相應的服務
  • 策略強制執行
  • 平衡:保持系統各個部分儘可能忙碌
  • 批處理三個指標
    • 吞吐量:最大化每小時運行工作數
    • 週轉時間:任務提交到運行結束的平均統計時間,時間越小越好
    • CPU利用率:保持cpu在所有時間內忙綠
  • 交互式系統指標
    • 響應時間:快速響應用戶請求
    • 均衡:滿足用戶期望
  • 實時系統
    • 滿足截止時間:避免錯過數據
    • 可預測性:避免在多媒體系統中品質降低

批處理系統調度算法

Frist-Come Frist-Served(FCFS)
  • 原理:顧名思義,就是先到的進程先調度,假設進程到達的順序是p1->p2->p3
    在這裏插入圖片描述
    p2等待時間是24ms,p3等待時間是27ms,所以平均等待時間17ms,現在假設進程到達的順序是p2->p3->p1那麼如下圖,平均等待時間是3ms
    在這裏插入圖片描述
  • 缺點
    1. 平均等待時間長
    2. 不能很好平衡CPU和I/O的利用率, 如果遇到計算密集型任務(會長期霸佔cpu),可能導致I/O空閒
最短作業優先(SJF)
  • 原理:每次調度都選擇下一次執行時間最短的作業執行,假設4個進程的需要的cpu突發時間如下圖
    在這裏插入圖片描述
    都是就緒狀態那麼調度順序將如下圖
    在這裏插入圖片描述
    平均等待時間爲7ms,如果用FCFS算法,平均等待時間可能爲10.25ms
  • 缺點
    1. 只有在進程可以同時就緒時,SJF纔是最優的
    2. 無法獲得下一次進程的cpu突發時間,可以利用一種指數平均方法來估計下一次cpu突發時間
      τn+1=αtn+(1α)τn\tau _{n+1} = \alpha t_n + (1-\alpha)\tau_n
      τn+1\tau_{n+1}代表第n+1次的預測值,tnt_n代表第n次實際時間,α\alpha代表歷史實際突發時間權重,0α10 \le \alpha \le 1,通常取12\frac{1}{2}
最短剩餘時間優先
  • 原理:基本思想和SJF相同,但是多了一點,最短剩餘時間優先是可以搶佔的,假設進程的到達時間和cpu突發時間如下圖
    在這裏插入圖片描述
    實際調度順序
    在這裏插入圖片描述
    p1最先到達,但是p2在p1執行1時到達,因爲p2的cpu突發時間比p1剩餘的cpu突發時間更短,因此p2搶佔p1的進程。平均等待時間是[(101)+(11)+(172)+(53)]/4=26/4=6.5[(10 − 1) + (1 − 1) + (17 − 2) + (5 − 3)]/4 = 26/4 = 6.5

交互式系統調度算法

輪轉調度(Round-Robin Scheduling RR)
  • 原理:類似FCFS算法,添加了搶佔和時間片概念。爲每一個進程分配一個時間片運行,在時間片結束前阻塞或結束,則CPU立即進行切換,或者進程用完分配的時間片,進程被掛起,切換就緒隊列的頭運行。時間片長度一般從10-100ms。就緒隊列可以看成是一個循環隊列,每個用完時間片的進程又加入到隊列尾部,結果如下圖
    在這裏插入圖片描述
  • 一個簡單的例子,假設進程cpu突發時間爲10,下圖是時間片爲1,6,12時,上下文切換的次數,可以看出時間片越短,上下文切換次數越多
    在這裏插入圖片描述
  • 缺點
    1. 時間片太長,RR算法可能會退化成FCFS
    2. 時間片太短,如上圖,上下文切換的次數將增加,進程週轉時間越大。
      浪費時間 = 上下文切換時間 / 時間片
優先級調度(Priority Scheduling)
  • 原理:每個進程都被分配了一個優先級,cpu將會被分配給高優先級的進程,同等優先級的進程採用FCFS算法調度
    1. 可搶佔優先級調度:當一個新的進程到達且優先級比當前cpu執行的進程高時,新進程可以搶佔當前進程的cpu
    2. 非可搶佔優先級調度:當一個新的進程到達且優先級比當前cpu執行的進程高時,只是簡單的將新進程加入隊列的頭部
  • 一個簡單例子,假設一個p1,p2…p5集合在時間0到達,cpu突發時間和優先級如下
    在這裏插入圖片描述
    它們的調度順序如下圖
    在這裏插入圖片描述
  • 缺點:飢餓,低優先級的進程可能無限期的等待,或者高優先級的進程一直霸佔CPU,有幾種解決方法
    1. 對於低優先級進程可以引入老化,定期提升一直未獲得cpu的低優先級進程的優先級。比如假設優先級範圍爲0-127,定時時間爲1s,一個最低優先級127的進程,只需要2min左右的時間就可以提升0
    2. 結合輪轉調度,同一優先級的進程會採用輪轉調度,比如
      在這裏插入圖片描述
      它們的調度順序會是這樣
      在這裏插入圖片描述
多級隊列調度
  • 原理:按不同進程的特徵,劃分爲不同的類別,然後不同類別的進程有不同的優先級,有獨立的調度隊列,採用不同的調度算法,比如
    在這裏插入圖片描述
    舉個例子,首先實時任務的優先級最高,因爲實時任務有deadline要求,其次是系統任務,然後是交互式任務,最低優先級爲批處理。每個優先級有自己的調度算法,比如交互式任務可以用RR調度,而批處理任務可以用FCFS調度
    在這裏插入圖片描述
多級反饋隊列調度
  • 原理:多級反饋隊列調度同樣是對於不同優先級的進程有多個隊列,進程在隊列之間是可以移動的,它的核心思想是CPU密集的進程會逐漸移動到低優先級隊列,而I/O密集和交互式進程可以在高優先級隊列保持低延遲響應。爲了防止飢餓,長時間等待的低優先級進程可以升級到高優先級隊列。每級隊列可以採用獨立的調度算法。
  • 簡單舉個例子,如下圖,有三級隊列,每個新來的進程會進入0級隊列,假設此時有1級隊列的進程正在執行,則會被新進程搶佔cpu。0、1級隊列都採用RR調度算法,2級採用FCFS調度算法,當0級的進程時間片用完後將降級加入1級隊列
    在這裏插入圖片描述
  • 多級反饋隊列調度關鍵參數
    1. 隊列數
    2. 每級隊列的調度算法
    3. 決策提升優先級的方法
    4. 決策降低優先級的方法
    5. 決策進程進入哪級隊列的方法

實時系統調度算法

實時系統和批處理和交互式系統不同,這裏先列出一些實時系統的基本概念

基本概念
  • 實時系統分類
    1. 軟實時系統:雖然也有時限要求,但是並不保證在deadline執行,錯過時限也不會導致嚴重的後果
    2. 硬實時系統:硬實時系統,嚴格的時限要求,任務必須在deadline執行,錯過了deadline意味着嚴重的後果
  • 最小延遲
    1. 事件延遲,從事件的發生到事件響應的事件
      • 中斷延遲:cpu收到中斷時,要做兩件事,第一檢查中斷類型,第二上下文切換保存當前正在執行線程的狀態,這段時間就是中斷延遲。有一個重要因素是當內核數據結構更新時是禁止響應中斷的,因此實時系統要求禁止響應中斷的時間非常短
        在這裏插入圖片描述
      • 分派延遲
        在這裏插入圖片描述
        • conflicts階段
          1. 搶佔正在運行的進程
          2. 低優先級進程釋放高優先級進程需要的資源
        • dispatch階段:調度高優先級進程到可用的cpu
基於優先級的調度
  • 原理:給實時任務分批較高的優先級
  • 缺點:基於優先級的搶佔式調度算法只能保證軟實時
Rate-Monotonic Scheduling(RMS)
  • 基本假設
    1. 假設調度週期性任務
    2. 假設每個任務進入系統會被分配一個固定優先級,週期越短優先級越高,週期越長優先級越低
    3. 假設任務的deadline是下一次執行前
  • 實際例子分析
    1. 假設第一個進程P1週期爲50,cpu時間爲20,第二個進程P2週期爲100,cpu時間爲35
      1. 計算cpu利用率
        Ucpu=20/50+35/100=0.75U_{cpu} = 20/50 + 35/100 = 0.75
      2. 假設p2先運行,那麼p1就無法在deadline50完成
        在這裏插入圖片描述
      3. 假設p1先運行
        在這裏插入圖片描述
    2. 假設第一個進程P1週期爲50,cpu時間爲25,第二個進程P2週期80,cpu時間爲35
      1. 計算cpu利用率,cpu利用率96%感覺可以運行,接下來分析一下調度
        Ucpu=25/50+35/80=0.96U_{cpu} = 25/50 + 35/80 = 0.96
      2. 無論如何調度,都無法滿足
        在這裏插入圖片描述
  • 結論:不能利用cpu最大利用率來確定是否能成功調度,應該取調度N個進程時最差的cpu利用率,當需要調度的任務cpu利用率超過該值時,無法調度,由此可見,RMS調度算法cpu利用率較低。N個進程最差的cpu利用率計算公式: UworstN=N(21N1)U_{worstN} = N(2^{\frac{1}{N}}-1)
Earliest-Deadline-First Scheduling(EDF)
  • 原理:根據任務的deadline動態調整進程的優先級。理論上是最優的算法,既能保證進程滿足deadline又能保證cpu有很好的利用率
  • 舉個簡單的例子,假設第一個進程P1週期爲50,cpu時間爲25,第二個進程P2週期80,cpu時間爲35
    在這裏插入圖片描述
  • 和RMS比較
    1. 不需要任務是週期性任務
    2. 不需要任務cpu執行時間是常數
Proportional Share Scheduling(PSS)
  • 原理:按比例分享cpu時間,admission-control會接收一個請求如果有足夠的比例份額,否則會拒絕請求,假設A需要50、B需要20、C需要15,當新來的D需要30,則會被拒絕

線程調度

上面所有算法都是以進程爲調度目標是爲了簡化,線程調度算法和進程的是一樣的,其實現代操作系統調度的都是內核線程。下面是上邊沒有介紹到的線程調度的區別

競爭範圍
  1. PCS:進程競爭範圍,在many-to-one和many-to-many線程模型中,用戶級線程調度器調度用戶線程運行在一個可用的LWP上,當用戶線程獲得可用LWP並不意味着該線程正運行在cpu上,還要取決於LWP的內核線程是否被調度獲得物理CPU
  2. SCS:系統競爭範圍,所有內核線程競爭cpu

多處理器調度

多處理器的種類
  • 多核心
  • 多線程內核(Intel的超線程)
  • NUMA系統
  • 異構多核處理器(ARM,多爲移動設備芯片)
非對稱多處理器
  • 所有的調度、i/o和其他系統活動處理都在同一個處理器上(master),其他處理器負責執行用戶代碼。
  • 優點,只有master處理器訪問系統數據,減少數據共享
  • 致命缺點:master處理器成爲瓶頸
對稱多處理器(SMP)
  • 所有處理器自調度
  • 調度隊列
    在這裏插入圖片描述
    1. a共用一個隊列,導致的問題是queue的競態問題,需要同步操作,否則可能兩個core取了同一個thread,那麼queue的鎖成了性能的瓶頸
    2. b最通用的方法,解決了通用queue鎖的瓶頸問題,而且可以有效利用緩存。有一個問題是工作量均衡問題,可用通過一個平衡算法來均衡各個處理器的工作量
多核心處理器memory stall問題
  • 當處理器執行代碼需要訪問主存時,因爲訪問主存很慢,導致會浪費很多cpu週期
    在這裏插入圖片描述
  • 解決辦法:芯片多線程技術(CMT),例如Intel的超線程,也就是我們平時總看到的i5雙核四線程,就是每個核心有兩個hardware thread
    在這裏插入圖片描述
    CMT處理器的結構,hardware thread共享物理芯片資源,比如緩存和流水線
    在這裏插入圖片描述
    CMT實現
    1. 粗粒度:發生高延遲時切換hardware thread,上下文切換需要刷新指令流水線,因此開銷高
    2. 細粒度:在更細的級別上,比如在指令週期的邊界
      實際兩級調度
      在這裏插入圖片描述
    3. 簡單輪轉調度算法:Ultra SPARC
    4. urgency優先級,每次切換時比較哪個優先級更高:Intel Itanium
負載均衡
  • Push migration:一個特殊任務定期檢查,如果檢查到不平衡,就會將線程從高負載的cpu移到空閒或低負載的cpu
  • Pull migration:當cpu空閒時會主動從高負載的cpu拉去任務
  • 負載均衡會導致一個問題,當一個已經執行過的線程因爲負載均衡被遷移到其他cpu時,其緩存將失效,需要的數據需要重新從主存加載
處理器親和
  • 定義:處理器親和指的是一個線程在一個處理器上運行,當處理器再次調度它時,有緩存的優勢,如果它再次執行的時候被遷移到其他cpu執行,那麼之前cpu的緩存將失效,並且當前cpu需要重新從主存中加載緩存,因此處理器親和的優勢可能會被負載均衡抵消
  • 軟親和:系統試圖保證現在在同一個cpu上調度,但是不能保證
  • 硬親和:系統提供了系統調用使進程可以指定一個cpu子集供進程的線程運行
  • 處理器親和在NUMA系統中非常重要,因爲每個cpu芯片有自己本地主存,訪問遠程主存是很慢的
    在這裏插入圖片描述

案例:Linux調度

分類調度
  • 默認的完全公平調度(CFS)(內核2.6.23)
    • 兩個概念
      1. nice value:範圍-20~+19,用來映射優先級,值越小優先級越高
      2. virtual run time:虛擬運行時間,當nice value爲0,該時間爲物理運行時間;當nice value越大,說明優先級越低,cpu時間比例越小,那麼該時間大於真實運行時間;反之優先級越高,cpu時間比例越高,該時間小於真實運行時間
    • 不採用固定時間片,而是採用比例,這個比例取決於nice value,值越小優先級越高,權重越高,調度週期內獲得cpu時間比例越高,也就是連續執行的時間替代時間片
    • 調度: 選擇虛擬運行時間最小的調度,因此nice value越小,優先級越高,得到調度的機會越多,就緒隊列實現是利用red-black Tree,當一個任務變成不可運行(例如阻塞)會從樹中刪除
      在這裏插入圖片描述
  • 實時調度
    • Linux分了兩個獨立的優先級範圍分別給實時任務(0-99)和普通任務(100-139,映射nice value~20-100,19-139)
負載均衡
  • 在NUMA架構中,採用分層調度域(一個cpu核心集合),負載均衡不會遷移線程到其他域,防止線程遠程訪問主存
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章