操作系统-处理机调度详解(调度层次及FCFS、SPF、RR等算法)
目錄
調度層次
處理機調度算法
評價指標
非剝奪式/搶占式
非搶占式優先級調度算法
先來先服務(FCFS)
短進程優先(SPF)
響應比優先算法(HRRN)
剝奪式/搶占式
最短剩余時間優先(SRTN)
時間片輪轉調度算法(RR)
搶占式優先級調度算法
多級反饋隊列
HRRN的Go實現
設計
全部代碼
結果
參考
調度層次
1.高級調度(High Level Scheduling)高級調度又稱長程調度或作業調度,它的調度對象是作業。主要功能是根據某種算法,決定將外存上處于后備隊列中的哪幾個作業調入內存,為它們創建進程、分配必要的資源,并將它們放入就緒隊列。高級調度主要用于多道批處理系統中,而在分時和實時系統中不設置高級調度。
2.低級調度(Low Level Scheduling)低級調度又稱為進程調度或短程調度,其所調度的對象是進程(或內核級線程)。其主要功能是,根據某種算法,決定就緒隊列中的哪個進程應獲得處理機,并由分派程序將處理機分配給被選中的進程。進程調度是最基本的一種調度,在多道批處理、分時和實時三種類型的OS中,都必須配置這級調度。
3.中級調度(Intermediate Scheduling)中級調度又稱為內存調度。引入中級調度的主要目的是,提高內存利用率和系統吞吐量。為此,應把那些暫時不能運行的進程,調至外存等待,此時進程的狀態稱為就緒駐外存狀態(或掛起狀態)。當它們已具備運行條件且內存又稍有空閑時,由中級調度來決定,把外存上的那些已具備運行條件的就緒進程再重新調入內存,并修改其狀態為就緒狀態,掛在就緒隊列上等待。
| 高級 | 外存->內存(面向作業) | 最低 | 無->創建態->就緒態 |
| 中級 | 外存->內存(面向進程) | 中等 | 掛起態->就緒態 (阻塞掛起->阻塞態) |
| 低級 | 內存->CPU | 最高 | 就緒態->運行態 |
處理機調度算法
我們以低級調度為例
進程調度的任務主要有:
- 保存處理機的現場信息。在進行調度時首先需要保存當前進程的處理機的現場信息,如程序計數器、多個通用寄存器中的內容等。
- 按某種算法選取進程。調度程序按某種算法從就緒隊列中選取一個進程,將其狀態改為運行狀態,并準備把處理機分配給它。
- 把處理器分配給進程。由分派程序把處理器分配給該進程,此時需要將選中進程的進程控制塊內有關處理機現場的信息裝入處理器相應的各個寄存器中,把處理器的控制權交予該進程,讓它從上次的斷點處恢復運行。
評價指標
CPU利用率
使用時間/總時間
系統吞吐量
完成的進程/總時間
周轉時間
- 周轉時間=進程完成時間-進程提交時間
- 平均周轉時間=所有進程周轉時間之和/進程數
- 帶權周轉時間=進程周轉時間/進程運行時間,帶權周轉時間>=1,越接近1,用戶滿意度越高
- 平均帶權周轉時間=帶權周轉時間/進程數
等待時間
等待時間=周轉時間-運行時間(等待I/O也算運行時間)
平均等待時間=等待時間/進程數
響應時間
用戶提交請求到首次產生響應所用的時間。
非剝奪式/搶占式
適合早期批處理操作系統
非搶占式優先級調度算法
選擇已到達的進程中,優先級最高的進行調度,若優先級相同,選擇先到達的。
例題
調度順序:P1->P3->P2->P4
- P1:0到達,運行7,7結束
- P2:2到達,運行4,12結束
- P3:4到達,運行1,8結束
- P4:5到達,運行4,16結束
周轉時間
- P1:7-0=7
- P2:12-2=10
- P3:8-4=4
- P4:16-5=11
平均周轉時間:8
帶權周轉時間:
- P1:7/7=1
- P2:10/4=2.5
- P3:4/1=4
- P4:11/4=2.75
平均帶權周轉時間:2.56
等待時間:
- P1:7-7=0
- P2:10-4=6
- P3:4-1=3
- P4:11-4=7
平均等待時間:4
先來先服務(FCFS)
first come,first service,按照到達的先后順序來調度
優點:公平,實現簡單,不會導致饑餓
缺點:對運行時間長的進程有利,對運行時間短的進程不友好
例題
有如下進程,根據到達時間和運行時間,計算進程的周轉時間、帶權周轉時間、等待時間,及對應平均時間。
- P1:0到達,運行7,7結束
- P2:2到達,運行4,11結束
- P3:4到達,運行1,12結束
- P4:5到達,運行4,16結束
周轉時間
- P1:7-0=7
- P2:11-2=9
- P3:12-4=8
- P4:16-5=11
平均周轉時間:8.75
帶權周轉時間:
- P1:7/7=1
- P2:9/4=2.25
- P3:8/1=8
- P4:11/4=2.75
平均帶權周轉時間:3.5
等待時間:
- P1:7-7=0
- P2:9-4=5
- P3:8-1=7
- P4:11-4=7
平均等待時間:4.75
短進程優先(SPF)
由于FCFS的缺點,于是提出了SPF。shortest process first,運行時間短的進程,優先級高。運行時間相同,先來的先運行。
優點:幾乎同時到達的情況下,可以得到最短的平均周轉時間和平均等待時間
缺點:對短作業有利,最長作業不友好,可能造成饑餓現象
例題
還是上面那個,調度順序P1->P3->P2->P4
- P1:0到達,運行7,7結束
- P2:2到達,運行4,12結束
- P3:4到達,運行1,8結束
- P4:5到達,運行4,16結束
周轉時間
- P1:7-0=7
- P2:12-2=10
- P3:8-4=4
- P4:16-5=11
平均周轉時間:8
帶權周轉時間:
- P1:7/7=1
- P2:10/4=2.5
- P3:4/1=4
- P4:11/4=2.75
平均帶權周轉時間:2.56
等待時間:
- P1:7-7=0
- P2:10-4=6
- P3:4-1=3
- P4:11-4=7
平均等待時間:4
響應比優先算法(HRRN)
考慮等待時間和運行時間,綜合了FCFS和SPF,對于長作業,等待時間長,響應比增大,不會饑餓
響應比=(等待時間+運行時間)/運行時間,響應比>=1,越大越優先,關注進程結束時剩余各進程響應比
例題
時刻表如下,綠色運行,黃色結束,括號內為響應比:
0:P1(7/7,7)
7:P3((3+1)/1=4)、P2((5+4)/4=2.25)、P4((2+4)/4=1.5)、P1
8:P2((6+4)/4=2.5)、P4((3+4)/4=1.75)、P3、P1
12:P4((7+4)/4=2.75)、P2、P3、P1
16:P4、P2、P3、P1
調度順序:P1->P3->P2->P4
周轉時間
- P1:7-0=7
- P2:12-2=10
- P3:8-4=4
- P4:16-5=11
平均周轉時間:8.75
帶權周轉時間:8
- P1:7/7=1
- P2:10/4=2.5
- P3:4/1=4
- P4:11/4=2.75
平均帶權周轉時間:2.56
等待時間:
- P1:7-7=0
- P2:10-4=6
- P3:4-1=3
- P4:11-4=7
平均等待時間:4.25
剝奪式/搶占式
適合分時、實時操作系統
最短剩余時間優先(SRTN)
例題
Shortest Remaining Time Next,最短剩余時間優先,剩余時間相同,先到達的先運行。關注有新進程到達時刻以及進程完成時刻。
時刻表如下,綠色代表運行的,黃色代表結束的
0:P1(7)
2:P2(4)、P1(5)
4:P3(1)、P2(2)、P1(5)
5:P2(2)、P4(4)、P1(5)、P3(0)
7:P4(4)、P1(5)、P2(0)、P3(0)
11:P1(5)、P4(0)、P2(0)、P3(0)
16:P1(0)、P4(0)、P2(0)、P3(0)
調度順序:P1->P2->P3->P2->P4->P1
- P1:0到達,運行7,16結束
- P2:2到達,運行4,7結束
- P3:4到達,運行1,5結束
- P4:5到達,運行4,11結束
周轉時間
- P1:16-0=16
- P2:7-2=5
- P3:5-4=1
- P4:11-5=6
平均周轉時間:7
帶權周轉時間:
- P1:16/7=2.28
- P2:5/4=1.25
- P3:1/1=1
- P4:6/4=1.5
平均帶權周轉時間:1.5
等待時間:
- P1:16-7=9
- P2:5-4=1
- P3:1-1=0
- P4:6-4=2
平均等待時間:3
時間片輪轉調度算法(RR)
Round-Robin,就緒隊列中,新到達的進程排在同時刻下處理機的進程前面。時間片未使用完,進程結束,主動釋放CPU。
如果時間片太大,使得每個進程都可以在一個時間片內就完成,則時間片輪轉調度算法退化為先來先服務調度算法,并且會增大進程響應時間。因此時間片不能太大。
另一方面,進程調度、切換是有時間代價的(保存、恢復運行環境),因此如果時間片太小,會導致進程切換過于頻繁,*系統會花大量的時間來處理進程切換,從而導致實際用于進程執行的時間比例減少。可見時間片也不能太小。
時間片為2
0:P1到達,P1運行
2:P2到達,P1運行一個時間片完畢,就緒隊列為P2(4)、P1(5),P2運行
4:P3到達,P2運行一個時間片完畢,就緒隊列為P1(5)、P3(1)、P2(2),P1運行
5:P4到達,就緒隊列P3(1)、P2(2)、P4(4)
6:P1運行一個時間片完畢,就緒隊列P3(1)、P2(2)、P4(4)、P1(3),P3運行
7:P3運行完畢,就緒隊列P2(2)、P4(4)、P1(3),P2運行
9:P2運行完畢,就緒隊列P4(4)、P1(3),P4運行
11:P4運行一個時間片完畢,就緒隊列P1(3)、P4(2),P1運行
13:P1運行一個時間片完畢,就緒隊列P4(2)、P1(1),P4運行
15:P4運行完畢,就緒隊列P1(1),P1運行
16:P1運行完畢
調度順序:P1->P2->P1->P3->P2->P4->P1->P4->P1
- P1:0到達,運行7,首次運行時間0,16結束
- P2:2到達,運行4,首次運行時間2,9結束
- P3:4到達,運行1,首次運行時間6,7結束
- P4:5到達,運行4,首次運行時間9,15結束
響應時間:
- P1:0-0=0
- P2:2-2=0
- P3:6-4=2
- P4:9-5=4
搶占式優先級調度算法
實時操作系統用的更多,關注就緒隊列改變(新到達進程優先級可能比正在運行的更高)和進程主動釋放CPU的時刻
優點:優先級可實時動態調整,適用于實時操作系統,很靈活
缺點:有源源不斷的高優先級進程到達,造成饑餓現象
- 系統進程優先級高于用戶進程
- 前臺進程優先級高于后臺進程
- 操作系統更偏好I/O型進程(或稱I/O繁忙型進程)
例題
調度順序:P1->P2->P3->P2->P4->P1
- P1:0到達,運行7,16結束
- P2:2到達,運行4,7結束
- P3:4到達,運行1,5結束
- P4:5到達,運行4,11結束
時刻表如下:
0:P1到達,就緒隊列:P1(7,1),P1運行
2:P2到達,就緒隊列:P2(4,2),P2運行,P1(5,1)進入就緒隊列
4:P3到達,就緒隊列:P3(1,3)、P1(5,1),P3運行,P2(2,2)進入就緒隊列
5:P3運行完畢,P4到達,就緒隊列:P2(2,2)、P4(4,2)、P1(5,1),P2運行
7:P2運行完畢,就緒隊列:P4(4,2)、P1(5,1),P4運行
11:P4運行完畢,就緒隊列:P1(5,1),P1運行
16:P1運行完畢
響應時間:
- P1:0-0=0
- P2:2-2=0
- P3:4-4=0
- P4:7-5=2
多級反饋隊列
前面的幾個
設置多級就緒隊列,各級隊列優先級從高到低,時間片從小到大。新進程到達時先進入第1級隊列,按FCFS原則排隊等待被分配時間片。若用完時間片進程還未結束,則進程進入下一級隊列隊尾。如果此時已經在最下級的隊列,則重新放回最下級隊列隊尾。只有第k級隊列為空時,才會為k+1級隊頭的進程分配時間片。被搶占處理機的進程重新放回原隊列隊尾。
FCFS和SPF太過簡單,我們就實現一個HRRN
HRRN的Go實現
設計
進程結構體的設計
// 進程 type Process struct{Pid int // 進程idPname string // 進程名Runtime int // 運行時間Priority int // 優先數 }優先數沒有用到,是為了以后想再實現其他算法時能夠兼容一下。
就緒隊列節點的設計
// 就緒隊列節點 type Node struct {p *Process // 進程Arrtime int // 到達時間Waittime int // 等待時間 }就緒隊列清楚進程什么時候到達,等待了多久。隊列就使用切片,如果使用C++實現,可以使用vector等stl。
處理機的設計
// 處理機 type Processor struct {p *Process }// 運行 func (p *Processor) Run() bool {println("running", p.p.Pname)p.p.Runtime --if p.p.Runtime == 0{println(p.p.Pname,"finish")p.p = nil // 進程移除內存return true}return false }處理機上面就是進程,有運行進程的功能,運行完畢將其移出內存。
全部代碼
package mainimport ("fmt" )// 進程 type Process struct{Pid int // 進程idPname string // 進程名Runtime int // 運行時間Priority int // 優先數 }// 固定優先數進程創建 func New(pid,runtime int,pname string) *Process {return &Process{Pid: pid,Pname: pname,Runtime: runtime,Priority: 0,} }// 就緒隊列節點 type Node struct {p *Process // 進程Arrtime int // 到達時間Waittime int // 等待時間 }// 進程移除就緒隊列 func Pop(b *[]Node,index int){//-----索引越界------if index<0 || index>=len(*b){return}//------前刪-------if index == 0{*b = (*b)[1:]return}//------尾刪-------if index == len(*b)-1{*b = (*b)[:len(*b)-1]return}//------中間刪------*b = append((*b)[0:index],(*b)[index+1:]...)return }// 處理機 type Processor struct {p *Process }// 運行 func (p *Processor) Run() bool {println("running", p.p.Pname)p.p.Runtime --if p.p.Runtime == 0{println(p.p.Pname,"finish")p.p = nil // 進程移除內存return true}return false }// 進程到達 func ProcessCome(queue []Node, time int) []Node {// 進程到達if time == 0{queue = append(queue, Node{p: New(0,7,"P1"),Arrtime: 0,})fmt.Printf("%d %s 到達\n",time,"P1")}if time == 2{queue = append(queue, Node{p: New(1,4,"P2"),Arrtime: 2,})fmt.Printf("%d %s 到達\n",time,"P2")}if time == 4{queue = append(queue,Node{p: New(2,1,"P3"),Arrtime: 4,})fmt.Printf("%d %s 到達\n",time,"P3")}if time == 5{queue = append(queue, Node{p: New(3,4,"P4"),Arrtime: 5,})fmt.Printf("%d %s 到達\n",time,"P4")}return queue }// 從就緒隊列選擇進程分配給處理機 func HRRN(queue []Node,p *Processor) {// 處理機上進程完成標志finish := truefor time:=0;;time++{queue = ProcessCome(queue,time)println("queue 長度:",len(queue))// 就緒隊列和處理機中都沒有進程,結束if len(queue) == 0 && p.p == nil{break}// 處理機上需要進程if finish == true{max := 0.0index := -1var runP Node// 遍歷就緒隊列for i,p := range queue{//println(p.p.Pname,p.Waittime)ratio := 1.0 + float64(p.Waittime)/float64(p.p.Runtime)fmt.Printf("%s響應比%f\n",p.p.Pname,ratio)if ratio > max{max = ratioindex = irunP = p}else if ratio < max{}else {// 響應比相同,先到達的先運行if runP.Arrtime > p.Arrtime{max = ratioindex = irunP = p}}}// 就緒隊列的進程放入處理機p.p = runP.p//就緒隊列進程移除Pop(&queue,index)}// 處理機運行進程if p.p != nil{finish = p.Run()}// 就緒隊列進程等待時間增加for i := range queue{queue[i].Waittime ++}}fmt.Println("就緒隊列沒有進程,處理機處于監聽狀態") }func main() {// 就緒隊列queue := make([]Node,0)// 處理機p := Processor{}HRRN(queue,&p) }結果
0 P1 到達
queue 長度: 1
P1響應比1.000000
running P1
queue 長度: 0
running P1
2 P2 到達
queue 長度: 1
running P1
queue 長度: 1
running P1
4 P3 到達
queue 長度: 2
running P1
5 P4 到達
queue 長度: 3
running P1
queue 長度: 3
running P1
P1 finish
queue 長度: 3
P2響應比2.250000
P3響應比4.000000
P4響應比1.500000
running P3
P3 finish
queue 長度: 2
P2響應比2.500000
P4響應比1.750000
running P2
queue 長度: 1
running P2
queue 長度: 1
running P2
queue 長度: 1
running P2
P2 finish
queue 長度: 1
P4響應比2.750000
running P4
queue 長度: 0
running P4
queue 長度: 0
running P4
queue 長度: 0
running P4
P4 finish
queue 長度: 0
就緒隊列沒有進程,處理機處于監聽狀態
就緒隊列和處理機都沒有進程的話,處理機應處于監聽狀態而不是關閉,這里沒有讓用戶輸入進程的信息,而是放到了ProcessCome函數中,所以就直接結束程序了,畢竟只是為了熟悉算法嘛。算法的核心在于處理機上進程結束時選擇響應比高的進程調度進處理機運行,響應比相同時,按到達時間,先來先服務。
參考
《計算機操作系統 湯小丹,湯小贏等》
總結
以上是生活随笔為你收集整理的操作系统-处理机调度详解(调度层次及FCFS、SPF、RR等算法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python - Opencv应用实例之
- 下一篇: web前端 运用CSS动画 实现图像的幻