磁盤調度在多道程序設計的計算機系統中,各個進程可能會不斷提出不同的對磁盤進行讀/寫操作的請求。由於有時候這些進程的發送請求的速度比磁盤響應的還要快,因此我們有必要為每個磁盤設備建立一個等待隊列,常用的磁盤調度算法有以下四種:
- 先來先服務算法(FCFS),
- 最短尋道時間優先算法(SSTF),
- 掃描算法(SCAN),
- 循環掃描算法(CSCAN)
代碼變量聲明:
1 vector<int> TrackOrder; //磁道初始序列 在函數中簡寫為 t 2 vector<int> MoveDistance; //磁頭移動距離 在函數中簡寫為 d 3 vector<int> List; //磁道訪問序列 在函數中簡寫為 list 4 double AverageDistance; //平均尋道距離 5 int begin; //初始磁道數 6 bool Direction; // 磁頭移動方向
1. 先來先服務(FCFS)算法
1.1 算法原理
這是一種比較簡單的磁盤調度算法。它根據進程請求訪問磁盤的先后次序進行調度。此算法的優點是公平、簡單,且每個進程的請求都能依次得到處理,不會出現某一進程的請求長期得不到滿足的情況。此算法由於未對尋道進行優化,在對磁盤的訪問請求比較多的情況下,此算法將降低設備服務的吞吐量,致使平均尋道時間可能較長,但各進程得到服務的響應時間的變化幅度較小。
1.2 代碼實現函數
1 void FCFS(vector<int> t, vector<int> &list, vector<int> &d, int begin){ 2 int length = t.size(); 3 int cur = begin; // 當前磁道數 4 for(int i = 0; i < length; i ++){ 5 list.push_back(t[i]); 6 d.push_back(abs( cur - list[i] )); 7 cur = list[i]; 8 } 9 }
1.3 結果截圖

2. 最短尋道時間優先(SSTF)算法
2.1 算法原理
該算法選擇這樣的進程,要求訪問的磁道與當前磁頭所在的磁道距離最近,以使每次的尋道時間最短,該算法可以得到比較好的吞吐量,但卻不能保證平均尋道時間最短。其缺點是對用戶的服務請求的響應機會不是均等的,因而導致響應時間的變化幅度很大。在服務請求很多的情況下,對內外邊緣磁道的請求將會無限期的被延遲,有些請求的響應時間將不可預期。
2.2 代碼實現函數
1 void SSTF(vector<int> t, vector<int> &list, vector<int> &d, int begin){ 2 int length = t.size(); 3 int cur = begin; // 當前磁道數 4 while(list.size() != length){ 5 list.push_back(t[0]); 6 int min = abs( cur - list.back() ), temp = 0; 7 for(int i = 0; i < t.size(); i ++) 8 if(abs( cur - t[i] ) < min ){ 9 temp = i; min = abs( cur - t[i] ); //利用絕對值找到最短距離 10 } 11 if(t[temp] != list.back()){ 12 list.pop_back(); 13 list.push_back(t[temp]); 14 } 15 d.push_back(min); 16 t.erase(t.begin() + temp); 17 cur = list.back(); 18 } 19 }
2.3 結果截圖

3. 掃描算法(SCAN)電梯調度
3.1 算法原理
掃描算法不僅考慮到預訪問的磁道與當前磁道的距離,更優先考慮的是磁頭的當前移動方向。例如,當磁頭正在自里向外移動時,掃描算法所選擇的下一個訪問對象應是其欲訪問的磁道既在當前磁道之外,又是距離最近的。這樣自里向外地訪問,直到再無更外的磁道需要訪問才將磁臂換向,自外向里移動。這時,同樣也是每次選擇這樣的進程來調度,即其要訪問的磁道,在當前磁道之內,從而避免了飢餓現象的出現。由於這種算法中磁頭移動的規律頗似電梯的運行,故又稱為電梯調度算法。此算法基本上克服了最短尋道時間優先算法的服務集中於中間磁道和響應時間變化比較大的缺點,而具有最短尋道時間優先算法的優點即吞吐量較大,平均響應時間較小,但由於是擺動式的掃描方法,兩側磁道被訪問的頻率仍低於中間磁道。
3.2 代碼實現函數
1 void SCAN(vector<int> t, vector<int> &list, vector<int> &d, int begin, bool dir){ 2 int length = t.size(), cur = begin; 3 sort(t.begin(),t.end()); 4 int temp; //指向分界點 5 for(int i = 0; i < length; i ++) 6 if(t[i] > cur){ 7 temp = i;break; 8 } 9 //先外后內 10 if( dir ){ 11 // 向外移動 12 for(int i = temp; i < length; i ++){ 13 list.push_back(t[i]); 14 d.push_back(t[i] - cur); 15 cur = t[i]; 16 } 17 // 向內移動 18 for(int i = temp - 1; i >= 0; i --){ 19 list.push_back(t[i]); 20 d.push_back(cur - t[i]); 21 cur = t[i]; 22 } 23 } 24 else{ 25 // 向內移動 26 for(int i = temp - 1; i >= 0; i --){ 27 list.push_back(t[i]); 28 d.push_back(cur - t[i]); 29 cur = t[i]; 30 } 31 // 向外移動 32 for(int i = temp; i < length; i ++){ 33 list.push_back(t[i]); 34 d.push_back(t[i] - cur); 35 cur = t[i]; 36 } 37 } 38 }
3.3 結果截圖

4. 循環掃描算法(CSCAN)
4.1 算法原理
循環掃描算法是對掃描算法的改進。如果對磁道的訪問請求是均勻分布的,當磁頭到達磁盤的一端,並反向運動時落在磁頭之后的訪問請求相對較少。這是由於這些磁道剛被處理,而磁盤另一端的請求密度相當高,且這些訪問請求等待的時間較長,為了解決這種情況,循環掃描算法規定磁頭單向移動。例如,只自里向外移動,當磁頭移到最外的被訪問磁道時,磁頭立即返回到最里的預訪磁道,即將最小磁道號緊接着最大磁道號構成循環,進行掃描。
4.2 代碼實現函數
1 void CSCAN(vector<int> t, vector<int> &list, vector<int> &d, int begin, bool dir){ 2 int length = t.size(), cur = begin; 3 sort(t.begin(),t.end()); 4 int temp; //指向分界點 5 for(int i = 0; i < length; i ++) 6 if(t[i] > cur){ 7 temp = i;break; 8 } 9 //向外移動 10 if( dir ){ 11 for(int i = temp; i < length; i ++){ 12 list.push_back(t[i]); 13 d.push_back(t[i] - cur); 14 cur = t[i]; 15 } 16 for(int i = 0; i < temp; i ++){ 17 list.push_back(t[i]); 18 d.push_back(abs(cur - t[i])); 19 cur = t[i]; 20 } 21 } 22 //向內移動 23 else{ 24 for(int i = temp - 1; i >= 0; i --){ 25 list.push_back(t[i]); 26 d.push_back(cur - t[i]); 27 cur = t[i]; 28 } 29 for(int i = length - 1; i >= temp; i --){ 30 list.push_back(t[i]); 31 d.push_back(abs(t[i] - cur)); 32 cur = t[i]; 33 } 34 } 35 }
4.3 結果展示

