首页 > 技术文章 > 操作系統-處理機調度和死鎖2(調度算法)

kaleidopink 2020-01-29 15:54 原文

操作系統-處理機調度和死鎖

5.調度算法

5.1 FCFS調度算法

FCFS(First Come First Served)調度算法是一種簡單的調度算法。該算法按照作業/進程進入隊列的先後順序進行調度。

5.2 短作業(短進程)優先算法

短作業優先調度算法(Shortest Job First,SJF)是指對短作業或短進程優先的算法,這裡短指的是運行時間的長短。但其缺點也很明顯:

  • 當不斷有短進程進入時,將使得長進程無限期延長,在批處理系統中可能比較適用。但對於實時系統,這種算法會導致部分進程不及時響應的問題。
  • 為考慮緊迫作業,不能保證緊迫作業優先處理。

5.3 高響應比優先調度算法(Highest Response-Ratio Next,HRN)

該算法通常用於作業調度。該算法同時考慮了作業的等待時間和所需的執行時間。響應比R定義為:

\[R = \frac{以等待時間 + 要求服務時間}{要求服務時間} \]

在每次挑選後備作業進行運行時,都要計算所有後備作業的響應比R值,選出R最高的作業進行執行。

5.4 優先級調度算法(Highest Priority First, HPF)

系統或用戶根據某種原則對作業\進程分配優先級,調度程序根據優先級調度。

  1. 優先級的類型

    優先級有兩類:靜態優先級動態優先級。靜態優先級在作業或進程開始執行之前就已經確定。通常優先級由某一範圍內的整數確定。確定優先級的依據如下:

    • 進程類型。通常系統進程優先級高於用戶進程優先級。系統進程也分為很多類型,同一類型也分有不同的優先級。

    • 進程對資源的要求。

    • 用戶要求。用戶根據進程的緊急程度確定一個優先級。

      通常將作業的優先級作為其所屬進程的優先級。

    動態優先級則把作業或進程的靜態特性和動態特性結合起來來確定其優先級,作業或進程的優先級在執行過程中是不斷變化的。例如可以規定,就緒隊列的進程隨著其等待時間的加長,其優先級逐漸增加,正在運行的進程其優先級逐漸降低。若所有進程有相同的優先級, 則最先進入隊列的進程優先獲得處理機,這也就是FCFS算法。高響應比算法實際就是動態優先級調度算法。

  2. 優先級調度算法的類型

    • 非搶佔式。非搶佔式中進程得到處理機後就一直執行下去,知道完成或遇到其它事件進入阻塞狀態。
    • 搶佔式。搶佔式中調度算法會從隊列中選取優先級最高的進程運行,如果隊列中出現了優先級更高的進程,則立即停止當前進程的運行,切換到優先級更高的進程運行。

5.5 時間片輪轉法

時間片輪轉法(Round-Robin)主要用於分時系統中的進程調度。系統按照先入先出的原則排成一個隊列,每個進程都可以運行一個時間片的時間,新來的進程加入到隊列的末尾。每當進程執行完其分配的時間片,就被加入到隊列的末尾。時間片是一個執行單位,量級是10~100ms。

5.6 多級隊列調度算法

該調度算法的核心思想是將系統中的就緒進程按照優先級分為兩級或多級隊列。進程調度時,首先從高優先級隊列中挑選進程,只有當高優先級隊列為空時,才從低優先級隊列挑選進程。

這種算法的性能很好,且容易實現,被目前流行的操作系統所採用,如UNIX、Linux和Windows NT等。

5.7 多級反饋隊列優先算法

該算法適用於進程調度。

該算法的實現思想是在多級隊列算法的基礎上加進“反饋措施”。具體描述如下:

  • 系統中設置多個就緒隊列,不同隊列設置不同的優先級
  • 各就緒隊列的時間片不同,高優先級時間片小,低優先級隊列時間片大。
  • 一個進程進入就緒隊列時,被放在第一級隊列(優先級最高)的末尾,各隊列按FCFS方式排列,每個進程運行一個時間片;如果一個進程沒有運行完成,則把它轉到下一級隊列的末尾。
  • 系統先運行第一隊列的進程,第一隊列為空後再運行第二隊列。以此類推。最後一個隊列採用時間片輪轉的方式進行運行。
  • 當比運行進程優先級更高的隊列中有一個新進程時,它將強制處理機,被搶佔的進程進入本隊列的末尾。

在單道批處理系統中,通常採用先來先服務調度算法,短作業優先算法和高響應比優先算法;分時系統通常採用時間片輪轉法,多級隊列輪轉及多級反饋隊列輪轉等調度算法;實時系統則採用搶佔式優先級、多級隊列輪轉及多級反饋隊列輪轉等策略。

6.Linux系統的調度算法

Linux系統的作業調度非常簡單,或者說根本沒有作業調度,作業一旦提交就直接進入內存,建立相應的進程,進入下一級調度。

6.1 Linux系統的進程調度策略

Linux系統的調度程序就是內核中schedule()函數,其主要任務就是在就緒隊列run_queue中選出一個進程並投入運行。schedule()函數的參數如下:

進程調度算法policy;

進程過程中剩餘的時間片counter;

進程靜態優先級priority。Linux2.4版本之後取消了這個變量,但是其默認值20還在作為常量繼續使用。

實時進程優先級Rt_priority;

用戶可控制的nice因子。

Linux系統提供了三種調度算法policy,這三種算法用戶可以通過宏定義來選擇。

調度策略標誌 所代表的的調度策略
#define SCHED_OTHER 普通的分時進程
#define SCHED_FIFO 先進先出的實時進程
#define SCHED_RR 基於優先級的輪轉算法
#define SCHED_YIELD 不是調度策略,表示進程讓出CPU

內核把進程分為實時進程普通進程。實時進程比普通進程優先,用戶可以通過sched_setschedule()函數改變調度策略。通過系統調用sys_setpriority()和sys_nice()改變其靜態優先級。一旦進程變為實時進程,其子進程也變為實時進程。

6.2 Linux系統的優先級調度策略

Linux系統優先級是一些短整數,Linux內核將優先級細分為靜態優先級、動態優先級和實時優先級。

  1. 靜態優先級

    靜態優先級是task_struct結構中的一個變量priority。其是在進程建立時繼承了父進程的優先級。可以通過系統調用nice()和setpriority()來改變優先級。且優先級在進程的整個運行過程中保持不變。

  2. 普通進程的調度策略

    對於普通進程即非實時進程,Linux採用搶佔式動態優先級調度算法。

    這種算法不設置進程就緒隊列,進程調度子程序schedule()總是給動態優先級最高的進程分配CPU。

    動態優先級是通過task_struct中的Counter變量來定義的,Counter表示搶佔式中斷調度前進程還能運行的時間。這個時間的單位是tick,即時鐘中斷的週期,在Linux中通常是10ms。如果一個進程的優先級55,那麼該進程至少還能再運行550ms的時間,在此期間不能發生搶佔式中斷調度。即在此期間只能進程快中斷處理,除非該進程因為等待I/O的原因主動退出運行態。

    從時間片的角度看,Linux系統中的時間片是動態時間片,不同進程的時間片不同,同一進程在不同時刻的時間片也不同。調度程序總是選取當前時間片最大的進程來運行。

    而Counter的值的變化規律遵循以下原則:

    在進程建立時,進程動態優先級的值是從父進程繼承的。之後,每當時鐘中斷發生時,當前運行進程的counter值就減一,而這種遞減情況遇到下面兩種情況會終止:

    • 當counter遞減到0時,進程就會在時鐘中斷處理過程中被迫從運行態進入就緒態。而處於就緒態的所有進程不一定動態優先級全為0,系統就每次都選取不為0的進程進入運行態。這樣直到處於就緒態的進程的動態優先級全為0,再根據所有進程(包括就緒態和等待態)靜態優先級來計算動態優先級。計算方法為:

      p->counter = (p->counter>>1) + p->priority; //p為每個進程的task_struct指針。
      

      再根據這些動態優先級重新調度進程。

    • 對於運行態的進程,可能counter還沒有遞減到0就因為要等待某個事件而進入了等待態。處於等待態的進程,其動態優先級可能增加,也可能不變,但是不可能減小。

      Tip:不管是運行態還是就緒態,Linux系統中都是用TASK_RUNNING來表示,只通過current變量即當前是否佔有CPU來區分。這在Linux的進程狀態中有詳細講到。

    counter帶來了效果為:

    (1) 等待態進程有更高的優先級,而且處於等待態時間越長的進程,其優先級越高。這就意味著I/O較多(意味著經常需要從運行態退出進入等待態)的進程優先級較高。

    (2) 計算較多的進程(通常從運行態退出後進入就緒態)優先級較低,因為通常其退出原因都是其時間片已經用完。

  3. 實時進程的調度策略

    因為實施進程對時間的要求比較高,因此Linux給實施進程增加了第三種優先級,稱為實時優先級。對於實時進程,Linux使用兩種調度策略:FIFS算法和RR算法。

推荐阅读