一、實驗目的
實驗程序模擬先來先服務FCFS,最短尋道時間優先SSTF,SCAN和循環SCAN算法的工作過程。假設有n個磁道號所組成的磁道訪問序列,給定開始磁道號m和磁頭移動的方向(正向或者反向),分別利用不同的磁盤調度算法訪問磁道序列,給出每一次訪問的磁頭移動距離,計算每種算法的平均尋道長度,本程序采用隨機數來產生磁道數。
二、實驗要求
算法所需的各種參數由輸入產生(手工輸入或者隨機數產生)。最后的結果要求是在運行四種算法的程序后,能夠輸出調度過程、平均尋道長度的正確結果。
三、實驗說明
(1) 先來先服務.(FCFS):
這是一種簡單的磁盤調度算法。它根據進程請求訪問磁盤的先后次序進行調度。此算法的優點是公平、簡單,且每個進程的請求都能依次得到處理,不會出現某一進程的請求長期得不到滿足的情況。但此算法由於未對尋道進行優化,致使平均尋道時間可能較長。
(2) 最短尋道時間優先(SSTF):
該算法選擇這樣的進程,其要求訪問的磁道與當前磁頭所在的磁道距離最近,以使每次的尋道時間最短,但這種調度算法卻不能保證平均尋道時間最短。
(3) 掃描算法(SCAN):
SCAN算法不僅考慮到欲訪問的磁道與當前磁道的距離,更優先考慮的是磁頭的當前移動方向。例如,當磁頭正在自里向外移動時,SCAN算法所選擇的下一個訪問對象應是其欲訪問的磁道既在當前磁道之外,又是距離最近的。這樣自里向外地訪問,直到再無更外的磁道需要訪問才將磁臂換向,自外向里移動。這時,同樣也是每次選擇這樣的進程來調度,即其要訪問的磁道,在當前磁道之內,從而避免了飢餓現象的出現。由於這種算法中磁頭移動的規律頗似電梯的運行,故又稱為電梯調度算法。
(4)循環掃描算法(CSCAN)
CSCAN算法是對掃描算法的改進。如果對磁道的訪問請求是均勻分布的,當磁頭到達磁盤的一端,並反向運動時落在磁頭之后的訪問請求相對較少。這是由於這些磁道剛被處理,而磁盤另一端的請求密度相當高,且這些訪問請求等待的時間較長,為了解決這種情況,循環掃描算法規定磁頭單向移動。例如,只自里向外移動,當磁頭移到最外的被訪問磁道時,磁頭立即返回到最里的欲訪磁道,即將最小磁道號緊接着最大磁道號構成循環,進行掃描
本系統划分為四個模塊:先來先服務算法模塊void FCFS(int array[],int m)、最短尋道時間優先算法模塊void SSTF(int array[],int m)、掃描算法模塊void SCAN(int array[],int m)、循環掃描模塊void CSCAN (int Han,int DiscL[])。
系統模塊圖
1 先來先服務算法模塊:void FCFS(int array[],int m)
輸入磁道號,按先來先服務的策略輸出磁盤請求序列,求平均尋道長度,輸出移動平均磁道數。
2 最短尋道時間優先算法模塊:void SSTF(int array[],int m)
將磁道號用冒泡法從小到大排序,輸出排好序的磁道序列,輸入當前磁道號,根據前磁道在已排的序列中的位置,選擇掃描的順序,求出平均尋道長度,輸出移動的平均磁道數。
3掃描算法模塊:void SCAN(int array[],int m)
將磁道號用冒泡法從小到大排序,輸出排好序的序列,輸入當前磁道號,選擇移動臂的移動方向,根據當前磁道在已排的序列中的位置,選擇掃描的順序,求出平均尋道長度,輸出移動的平均磁道數。
4 循環掃描算法模塊:void CSCAN(int array[],int m)
將磁道號用冒泡法從小到大排序,輸出排好序的序列,輸入當前磁道號,規定移動臂單向反復的從內向外移動,根據當前磁道在已排的序列中的位置,選擇掃描的順序,求出平均尋道長度,輸出移動的平均磁道數。
1、先來先服務(FCFS)
這是一種簡單的磁盤調度算法。它根據進程請求訪問磁盤的先后次序進行調度。此算法的優點是公平、簡單,且每個進程的請求都能依次得到處理,不會出現某一進程的請求長期得不到滿足的情況。但此算法由於未對尋道進行優化,致使平均尋道時間可能較長。
實現函數:void FCFS(int Han,int DiscL[])
先來先服務算法(FCFS)流程圖:
2、最短尋道時間優先(SSTF)
該算法選擇這樣的進程,其要求訪問的磁道與當前磁頭所在的磁道距離最近,以使每次的尋道時間最短,但這種調度算法卻不能保證平均尋道時間最短。
實現函數:void SSTF(int Han,int DiscL[])
最短尋道時間優先流程圖:
3、掃描算法(SCAN)
SCAN算法不僅考慮到欲訪問的磁道與當前磁道的距離,更優先考慮的是磁頭的當前移動方向。例如,當磁頭正在自里向外移動時,SCAN算法所選擇的下一個訪問對象應是其欲訪問的磁道既在當前磁道之外,又是距離最近的。這樣自里向外地訪問,直到再無更外的磁道需要訪問才將磁臂換向,自外向里移動。這時,同樣也是每次選擇這樣的進程來調度,即其要訪問的磁道,在當前磁道之內,從而避免了飢餓現象的出現。由於這種算法中磁頭移動的規律頗似電梯的運行,故又稱為電梯調度算法。
實現函數:int SCAN(int Han,int DiscL[],int x,int y)
(4)循環掃描算法(CSCAN)
CSCAN算法在SCAN算法的基礎上規定了刺頭單向移動,減少了進程的請求延遲。例如:只是自理向外移動,當磁頭移到最外的磁道並訪問后,磁頭立即返回到最里的欲訪問磁道,亦即將最小的磁道號緊接着最大的磁道號構成循環,進行循環掃描。
實現函數:void CSCAN(int Han,int DiscL[])
源代碼:
// 123123123.cpp : 定義控制台應用程序的入口點。 // #include "stdafx.h" #include "stdio.h" #include "stdlib.h" void CopyL(int Sour[],int Dist[] ,int x); //數組Sour復制到數組Dist,復制到x個數 void SetDI(int DiscL[]); //隨機生成磁道數 void Print(int Pri[],int x); //打印輸出數組Pri void DelInq(int Sour[],int x,int y); //數組Sour把x位置的數刪除,並把y前面的數向前移動,y后的數保持不變(即會出現2個y) void FCFS(int Han,int DiscL[]); //先來先服務算法(FCFS) void SSTF(int Han,int DiscL[]); //最短尋道時間優先算法(SSTF) int SCAN(int Han,int DiscL[],int x,int y); //掃描算法(SCAN) void CSCAN(int Han,int DiscL[]); //循環掃描算法(CSCAN) void N_Step_SCAN(int Han1,int DiscL[]); //N步掃描算法(NStepScan) void PaiXu(); //尋道長度由低到高排序 void Pri(); int NAll=0; int Best[5][2]; //用作尋道長度由低到高排序時存放的數組 int Limit=0; //輸入尋找的范圍磁道數i int Jage; float Aver=0; int main() { int i; int DiscLine[10]; //聲明准備要生成的隨機磁道號的數組 int Hand; //磁道數 int Con=1; int n; while(Con==1) { Jage=0; printf(" 請輸入初始的磁道數(0<n<65536):"); scanf("%d",&Hand); printf(" + 輸入尋找的范圍:"); scanf("%d",&Limit); if(Limit<=0||Limit>65536){ printf("超出范圍!"); } else{ printf(" ╭═══════════════╮ \n"); printf(" ║ 操作系統課程實驗 ║ \n"); printf(" ╭═════┤ 磁盤調度算法 ├═════╮ \n"); printf(" ║ ║ ║ ║ \n"); printf(" ║ ╰═══════════════╯ ║ \n"); printf(" ║ 1.先來先服務算法(FCFS) ║ \n"); printf(" ║ ║ \n"); printf(" ║ 2.最短尋道時間優先算法(SSTF) ║ \n"); printf(" ║ ║ \n"); printf(" ║ 3.掃描算法(SCAN) ║ \n"); printf(" ║ ║ \n"); printf(" ║ 4.循環掃描算法(CSCAN) ║ \n"); printf(" ║ ║ \n"); printf(" ║ ║ \n"); printf(" ║ ╭───────────────────────╮ ║ \n"); printf(" ╰═┤ 請輸入你的選擇的算法(輸入0離開) ├═╯ \n"); printf(" ╰───────────────────────╯ \n"); scanf("%d",&n); if(n==0) exit(0); printf(" "); switch(n) { case 1: SetDI(DiscLine); //隨機生成磁道數 FCFS(Hand,DiscLine); //先來先服務算法(FCFS) break; case 2: SetDI(DiscLine); //隨機生成磁道數 SSTF(Hand,DiscLine); //最短尋道時間優先算法(SSTF) break; case 3: SetDI(DiscLine); //隨機生成磁道數 SCAN(Hand,DiscLine,0,9); //掃描算法(SCAN) break; case 4: SetDI(DiscLine); //隨機生成磁道數 CSCAN(Hand,DiscLine); //循環掃描算法(CSCAN) break; } printf(" + 是否繼續(按0結束,按1繼續)?"); scanf("%5d",&Con); } } } //數組Sour復制到數組Dist,復制到x個數 void CopyL(int Sour[],int Dist[] ,int x) { int i; for(i=0;i<=x;i++) { Dist[i]=Sour[i]; } } //打印輸出數組Pri void Print(int Pri[],int x) { int i; for(i=0;i<=x;i++) { printf("%5d",Pri[i]); } } //隨機生成磁道數 void SetDI(int DiscL[]) { int i; for(i=0;i<=9;i++) { DiscL[i]=rand()%Limit;//隨機生成10個磁道號 } printf("+ 需要尋找的磁道號:"); Print(DiscL,9); //輸出隨機生成的磁道號 printf(" \n"); } //數組Sour把x位置的數刪除,並把y前面的數向前移動,y后的數保持不變(即會出現2個y) void DelInq(int Sour[],int x,int y) { int i; for(i=x;i<y;i++) { Sour[i]=Sour[i+1]; x++; } } //先來先服務算法(FCFS) void FCFS(int Han,int DiscL[]) { int RLine[10]; //將隨機生成的磁道數數組Discl[]復制給數組RLine[] int i,k,All,Temp; //Temp是計算移動的磁道距離的臨時變量 All=0; //統計全部的磁道數變量 k=9; //限定10個的磁道數 CopyL(DiscL,RLine,9); //復制磁道號到臨時數組RLine printf(" + 按照FCFS算法磁道的訪問順序為:"); All=Han-RLine[0]; for(i=0;i<=9;i++) { Temp=RLine[0]-RLine[1];//求出移動磁道數,前一個磁道數減去后一個磁道數得出臨時的移動距離 if(Temp<0) Temp=(-Temp);//移動磁道數為負數時,算出相反數作為移動磁道數 printf("%5d",RLine[0]); All=Temp+All;//求全部磁道數的總和 DelInq(RLine,0,k);//每個磁道數向前移動一位 k--; } Best[Jage][1]=All;//Best[][1]存放移動磁道數 Best[Jage][0]=1; //Best[][0]存放算法的序號為:1 Jage++;//排序的序號加1 Aver=((float) All)/10;//求平均尋道次數 printf("\n"); printf(" + 移動磁道數:<%5d> ",All);printf("\n"); printf(" + 平均尋道長度:*%0.2f* \n",Aver);printf("\n"); } //冒泡排序 int* Bubble(int pArr[],int nFirst,int nEnd) { int nTemp=0; for(int i=nFirst;i<nEnd;++i) { for(int j=i;j<nEnd;++j) { if(pArr[i]>pArr[j]) { nTemp=pArr[i]; pArr[i]=pArr[j]; pArr[j]=nTemp; } } } return pArr; } //最短尋道時間優先算法(SSTF) void SSTF(int Han,int DiscL[]) { int temp; int k=1,n=10; int l,r; int i,j,all=0; //將磁道號按遞增排序 DiscL=Bubble(DiscL,0,10); printf("\n+ 按照SSTF算法磁道的訪問順序為::"); //判斷標志位Han左、右兩邊的偏移量大小 if(DiscL[n-1]<=Han)//當前磁頭位置大於最外圍欲訪問磁道 { for(i=n-1;i>=0;i--) { printf("%d ",DiscL[i]); } all=Han-DiscL[0]; } else if(DiscL[0]>=Han)//當前磁頭位置小於最里欲訪問磁道 { for(i=0;i<n;i++) { printf("%d ",DiscL[i]); } all=DiscL[n-1]-Han; } else { while(DiscL[k]<Han)//確定當前磁道在已排的序列中的位置 { k++; } l=k-1;//在磁頭位置的前一個欲訪問磁道 r=k;//磁頭欲訪問磁道 while((l>=0)&&(r<n)) { if((Han-DiscL[l])<=(DiscL[r]-Han))//選擇離磁頭近的磁道 { printf("%d ",DiscL[l]); all+=Han-DiscL[l]; Han=DiscL[l]; l=l-1; } else { printf("%d ",DiscL[r]); all+=DiscL[r]-Han; Han=DiscL[r]; r=r+1; } } if(l=-1)//磁頭位置里側的磁道已訪問完 { for(j=r;j<n;j++)//訪問磁頭位置外側的磁道 { printf("%d ",DiscL[j]); } all+=DiscL[n-1]-DiscL[0]; } if(r==n)//磁頭位置外側的磁道已訪問完 { for(j=k-1;j>-1;j--) //訪問磁頭位置里側的磁道 { printf("%d ",DiscL[j]); } all+=DiscL[n-1]-DiscL[0]; } } printf("\n + 移動磁道數:<%5d> \n",all); printf(" + 平均尋道長度:*%0.2f* \n",all/10.0); } //掃描算法(SCAN) int SCAN(int Han,int DiscL[],int x,int y) { int temp; int k=1,n=10; int l,r; int i,j,all=0; DiscL=Bubble(DiscL,x,y); //printf("按遞增順序排好的磁道為:"); //for( i=0;i<n;i++) //{ // printf("%d ",DiscL[i]); //} //以下算法確定磁道訪問順序 if(DiscL[n-1]<=Han) //磁頭位置大於最外圍欲訪問磁道 { for(i=n-1;i>=0;i--) printf("%d ",DiscL[i]); all=Han-DiscL[0]; } else if(DiscL[0]>=Han) //磁頭位置小於最里欲訪問磁道 { for(i=0;i<n;i++) printf("%d ",DiscL[i]); all=DiscL[n-1]-Han; } else //磁頭位置在最里側磁道與最外側磁道之間 { int d; while(DiscL[k]<Han) { //確定當前磁道在已排的序列中的位置 k++; } l=k-1;//在磁頭位置的前一個欲訪問磁道 r=k; //磁頭欲訪問磁道 printf("\n請輸入當前磁頭移動的方向 (0 表示向內 ,1表示向外) : "); scanf("%d",&d); //確定磁頭訪問的方向 printf("按照SCAN算法訪問順序為:"); if(d==0||d==1) { if(d==0) //磁頭向內 { for(j=l;j>=0;j--) { printf("%d ",DiscL[j]); } for(j=r;j<n;j++) { printf("%d ",DiscL[j]); } all=Han-2*DiscL[0]+DiscL[n-1]; } if(d==1) //磁頭向外 { for(j=r;j<n;j++) { printf("%d ",DiscL[j]); } for(j=l;j>=0;j--) { printf("%d ",DiscL[j]); } all=2*DiscL[n-1]-Han-DiscL[0]; } } else printf("請輸入0或1!"); } printf("\n + 移動磁道數:<%5d> \n",all); printf(" + 平均尋道長度:*%0.2f* \n",all/10.0); return 0; } //循環掃描算法(CSCAN) void CSCAN(int Han,int DiscL[]) { int temp; int l,r; int i,j,all=0; int k=1,n=10; //對訪問磁道按由小到大順序排列輸出 DiscL=Bubble(DiscL,0,10); //printf("按遞增順序排好的磁道為:"); //for( i=0;i<n;i++) //{ // printf("%d ",DiscL[i]); //} if(DiscL[n-1]<=Han)//磁頭位置大於最外圍欲訪問磁道 { for(i=0;i<n;i++) printf("%d ",DiscL[i]); all=Han-2*DiscL[0]+DiscL[n-1]; } else if(DiscL[0]>=Han)//磁頭位置小於最里欲訪問磁道 { for(i=0;i<n;i++) printf("%d ",DiscL[i]); all=DiscL[n-1]-Han; } else //磁頭位置在最里側磁道與最外側磁道之間 { int d; while(DiscL[k]<Han) { k++; } l=k-1;//在磁頭位置的前一個欲訪問磁道 r=k; //磁頭欲訪問磁道 printf("\n請輸入當前磁頭移動的方向 (0 表示向內 ,1表示向外) : "); scanf("%d",&d); //確定磁頭訪問的方向 printf("按照CSCAN算法訪問順序為:"); if(d==0||d==1) { if(d==1) //磁頭向外側訪問 { for(j=r;j<n;j++)//先訪問外側磁道再轉向最里欲訪問磁道 { printf("%d ",DiscL[j]); } for(j=0;j<r;j++) { printf("%d ",DiscL[j]); } all=2*DiscL[n-1]-Han-2*DiscL[0]+DiscL[l]; } if(d==0) //磁頭向內側訪問 { for(j=r-1;j>=0;j--) { printf("%d ",DiscL[j]); } for(j=n-1;j>=r;j--) { printf("%d ",DiscL[j]); } all=2*DiscL[n-1]-2*DiscL[0]+Han-DiscL[r]; } } else printf("請輸入0或1!"); } printf("\n + 移動磁道數:<%5d> \n",all); printf(" + 平均尋道長度:*%0.2f* \n",all/10.0); }