磁碟排程演算法設計與實現——C語言
一、設計分析
共享裝置的典型代表為磁碟,磁碟物理塊的地址由柱面號、磁頭號、扇區號來指定,完成磁碟某一個物理塊的訪問要經過三個階段:尋道時間Ts、旋轉延遲時間Tw和讀寫時間Trw。
尋道時間Ts是磁頭從當前磁軌移動到目標磁軌所需要的時間;旋轉延遲時間Tw是當磁頭停留在目標磁軌後,目標物理塊從當前位置旋轉到磁頭位置的時間;讀寫時間Trw是目標物理塊內容與記憶體中對應交換的時間。磁碟排程的原則是公平和高吞吐量,衡量指標有訪問時間T和平均訪問時間Ta:
T=Ts+Tw+Trw
Ta=Tsa+Twa+Trwa
尋道時間和旋轉延遲時間成為排程演算法的主要考慮因素。減少訪問時間就是要減少尋道時間和旋轉延遲時間。
(1)先來先服務演算法(FCFS)First Come First Service
這是一種比較簡單的磁碟排程演算法。它根據程序請求訪問磁碟的先後次序進行排程。此演算法的優點是公平、簡單,且每個程序的請求都能依次得到處理,不會出現某一程序的請求長期得不到滿足的情況。此演算法由於未對尋道進行優化,在對磁碟的訪問請求比較多的情況下,此演算法將降低裝置服務的吞吐量,致使平均尋道時間可能較長,但各程序得到服務的響應時間的變化幅度較小。
(2)最短尋道時間優先演算法(SSTF) Shortest Seek Time First
該演算法選擇這樣的程序,其要求訪問的磁軌與當前磁頭所在的磁軌距離最近,以使每次的尋道時間最短,該演算法可以得到比較好的吞吐量,但卻不能保證平均尋道時間最短。其缺點是對使用者的服務請求的響應機會不是均等的,因而導致響應時間的變化幅度很大。在服務請求很多的情況下,對內外邊緣磁軌的請求將會無限期的被延遲,有些請求的響應時間將不可預期。
(3)掃描演算法(SCAN)電梯排程
掃描演算法不僅考慮到欲訪問的磁軌與當前磁軌的距離,更優先考慮的是磁頭的當前移動方向。例如,當磁頭正在自裡向外移動時,掃描演算法所選擇的下一個訪問物件應是其欲訪問的磁軌既在當前磁軌之外,又是距離最近的。這樣自裡向外地訪問,直到再無更外的磁軌需要訪問才將磁臂換向,自外向裡移動。這時,同樣也是每次選擇這樣的程序來排程,即其要訪問的磁軌,在當前磁軌之內,從而避免了飢餓現象的出現。由於這種演算法中磁頭移動的規律頗似電梯的執行,故又稱為電梯排程演算法。此演算法基本上克服了最短尋道時間優先演算法的服務集中於中間磁軌和響應時間變化比較大的缺點,而具有最短尋道時間優先演算法的優點即吞吐量較大,平均響應時間較小,但由於是擺動式的掃描方法,兩側磁軌被訪問的頻率仍低於中間磁軌。
(4)迴圈掃描演算法(C-SCAN)
在掃描演算法的基礎上規定磁頭單向移動來提供服務,回返時直接快速移動至起始端而不服務任何請求。
二、設計及實現
(1)平臺:Linux
語言:c
(2)設計思路
(3)源程式
#include<stdio.h>
int num,sum,kai,max;
int m=0;
int n=0;
int s[100];
int s1[100];
int c1[50];
int c2[50];
void creat()
{
printf("----------------------------------------------------\n");
printf("請輸入從哪個磁軌開始:\t\n");
printf("----------------------------------------------------\n");
scanf("%d",&kai);
printf("----------------------------------------------------\n");
printf("請輸入最長磁軌號:\n");
printf("------------------------------------------------------\n");
scanf("%d",&max);
printf("------------------------------------------------------\n");
printf("請輸入磁軌的個數:\n");
printf("------------------------------------------------------\n");
scanf("%d",&num);
for(int j=0;j<num;j++)
{
printf("請輸入第%d個磁軌\n",j+1);
scanf("%d",&s[j]);
if(s[j]>max)
{
printf("ERROR\n");
break;
}
for(int i=0;i<j;i++)
if(s[j]==s[i])
j--;
}
printf("被訪問的下一個磁軌\n");
for(int i=0;i<num;i++)
{
printf("\t%d\t\n",s[i]);
}
int su=kai;
int t;
for(int i=0;i<num;i++)
if(su>s[i])
c1[m++]=s[i];
else
c2[n++]=s[i];
for(int i=0;i<m;i++)
for(int j=i;j<m;j++)
if(c1[i]<c1[j])
{t=c1[i];c1[i]=c1[j];c1[j]=t;}
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
if(c2[i]>c2[j])
{t=c2[i];c2[i]=c2[j];c2[j]=t;}
}
void FCFS()
{
printf("先來先服務 FCFS\n");
printf("被訪問的下一個磁軌\t\t\t磁軌號移動距離\n");
int su=kai;
sum=0;
for(int i=0;i<num;i++)
{ if(su<s[i])
s1[i]=s[i]-su;
else
s1[i]=su-s[i];
su=s[i];
sum+=s1[i];
}
for(int i=0;i<num;i++)
{
printf("\t%d\t\t\t\t\t%d\t\t\n",s[i],s1[i]);
}
printf("尋道長度:%d\n",sum);
}
void SSTF()
{
printf("最短尋道 SSTF:\n");
printf("被訪問的下一個磁軌\t\t\t磁軌號移動距離\n");
int su=kai;
int s2[100];
sum=0;
for(int i=0;i<m;i++)
s2[i]=c1[i];
for(int i=0;i<n;i++)
s2[i+m]=c2[i];
for(int i=0;i<num;i++)
{ if(su<s2[i])
s1[i]=s2[i]-su;
else
s1[i]=su-s2[i];
su=s2[i];
sum+=s1[i];
}
for(int i=0;i<num;i++)
{
printf("\t%d\t\t\t\t\t%d\t\t\n",s2[i],s1[i]);
}
printf("尋道長度:%d\n",sum);
}
void SCAN()
{
printf("掃描演算法 SCAN:\n");
printf("被訪問的下一個磁軌:\t\t\t磁軌號移動距離:\n");
int su=kai;
int s2[100];
sum=0;
for(int i=0;i<n;i++)
s2[i] =c2[i];
for(int i=0;i<m;i++)
s2[i+n]=c1[i];
for(int i=0;i<num;i++)
{ if(su<s2[i])
s1[i]=s2[i]-su;
else
s1[i]=su-s2[i];
su=s2[i];
sum+=s1[i];
}
for(int i=0;i<num;i++)
{
printf("\t%d\t\t\t\t\t%d\t\t\n",s2[i],s1[i]);
}
printf("尋道長度:%d\n",sum);
}
void CSAN()
{
printf("迴圈掃描 CSAN:\n");
printf("被訪問的下一個磁軌:\t\t\t磁軌號移動距離:\n");
int su=kai;
int j=0;
int s2[100];
sum=0;
for(int i=0;i<n;i++)
s2[i] =c2[i];
for(int i=m-1;i>=0;j++,i--)
s2[j+n]=c1[i];
for(int i=0;i<num;i++)
{ if(su<s2[i])
s1[i]=s2[i]-su;
else
s1[i]=su-s2[i];
su=s2[i];
sum+=s1[i];
}
//sum=sum/num;
for(int i=0;i<num;i++)
{printf("\t%d\t\t\t\t\t%d\t\t\n",s2[i],s1[i]);
}
printf("尋道長度:%d\n",sum);
}
void MENU()
{
printf("磁碟排程\n");
printf("---------------------------------------\n");
printf("1.建立磁軌\t 2.先來先服務 FCFS\t 3.最短尋道 SSTF\t 4.掃描演算法 SCAN\t 5.迴圈掃描演算法 CSCAN\t 6.退出 EXIT\n");
int menuchoice;
scanf("%d",&menuchoice);
if(menuchoice!=1&&menuchoice!=6)
{
printf("請先建立磁軌\n");
}
if(menuchoice==6)
{
printf("謝謝使用!");
}
else
{
creat();
printf("磁碟排程\n");
P:printf("---------------------------------------\n");
printf("1.建立磁軌\t 2.先來先服務 FCFS\t 3.最短尋道 SSTF\t 4.掃描演算法 SCAN\t 5.迴圈掃描演算法 CSCAN\t 6.退出 EXIT\n");
scanf("%d",&menuchoice);
if(menuchoice>6||menuchoice<1) {
printf("沒看到菜單隻有1-6嗎?搞事情啊!!!\n");
goto P;
}
switch(menuchoice)
{
case 2:
FCFS();
goto P;
case 3:
SSTF();
goto P;
case 4:
SCAN();
goto P;
case 5:
CSAN();
goto P;
case 6:
printf("謝謝使用!");
break;
}
}
}
int main()
{
MENU();
return 0;
}
三、測試資料及結果
(1) 測試資料
開始磁軌:125
磁軌個數:10
磁軌號:23,46,543,122,5,126,2,233,121,50
(2)執行結果
->執行程式,根據選單選擇操作。如圖,選擇1、建立磁軌
->當未建立磁軌而直接選擇其他選項時,提示“請先建立磁軌”
->建立磁軌後,選擇演算法,進行排序。並求出 被訪問磁軌順序,磁軌號移動距離,尋到長度。
FCFS:
CSAN:
SSTF:
SCAN:
EXIT:
四、結果分析
磁碟演算法排程的比較以及多次實驗得出了以下結果:
1、最短尋到SSTF的尋道長度最短;但不能保證尋道時間最短,可能出現“飢餓現象”;
2、FCFS演算法具有公平性,但不適合大量程序的訪問;平均尋道距離大,僅應用在磁碟I/O較少的場合。
3、SCAN演算法對最近掃描過的區域不公平,它在訪問區域性性方面不如FCFS演算法和SSTF演算法好,不利於遠離磁頭一端的訪問;
4、改進了SCAN演算法掃描區域不公平現象。