【操作系統】多級反饋隊列算法


  1. 原理介紹
  1. RR時間片輪轉原理

      在采用時間片輪轉算法中,所有的就緒進程按FCFS策略排成一個就緒隊列。系統可設置每隔一定時間便產生一次中斷,去激活進程調度程序進行調度,把CPU分配給隊首進程,並令其執行一個時間片。當它運行完畢后,又把處理機分配給就緒隊列中新的隊首進程,也讓它執行一個時間片。這樣,就可以保證就緒隊列中的所有進程在確定的時間段內,都能獲得一個時間片的處理機時間。

    在RR調度算法中進程的切換,可分為兩種情況:①若一個時間片尚未用完,正在運行的進程便已經完成,就立即激活調度程序,將它從就緒隊列中刪除,再調度就緒隊列中隊首的進程運行,並啟動一個新的時間片。②在一個時間片用完時,計時器中斷處理程序被激活。如果進程尚未運行完畢,調度程序將把它送往就緒隊列的末尾。

   

  2.多級反饋隊列調度機制

    設置多個就緒隊列。在系統中設置多個就緒隊列,並為每個隊列賦予不同的優先。第一個隊列的優先級最高,第二個次之,其余隊列的優先級逐個降低。該算法為不同列中的進程所賦予的執行時間片的大小也各不相同,在優先級愈高的隊列中,其時間片愈小。

    每個隊列都采用FCFS算法。當新進程進入內存后,首先將它放入第一隊列的末尾,按FCFS原則等待調度。當輪到該進程執行時,如它能在該時間片內完成,便可撤離系統。否則,即它在一個時間片結束時尚未完成,調度程序將其轉入第二隊列的末尾等待調度;如果它在第二隊列中運行個時間片后仍未完成, 再依次將它放入第三隊列...依此類推。當進程最后被降到第n隊列后,在第n隊列中便采取按RR方式運行。

    按隊列優先級調度。調度程序首先調度最高優先級隊列中的諸進程運行,僅當第一隊列空閑時才調度第二隊列中的進程運行;僅當第1到(i-1)所有隊列均空時,才會調度第i隊列中的進程運行。如果處理機正在第i隊列中為某進程服務時又有新進程進入任一優先級較高的隊列,此時須立即把正在運行的進程放回到第i隊列的末尾,而把處理機分配給新到的高優先級進程。

  

    2.設計原理

    PCB設計

    設計結構體PCB,其中包括進程的標識符,到達時間,服務時間,完成時間,周轉時間和帶權周轉時間。利用動態數組將所有進程存儲起來。

    

 1 struct PCB
 2 
 3 {
 4 
 5 int ID; //標識符
 6 
 7 int ComeTime; //到達時間
 8 
 9 int ServerTime; //服務時間
10 
11 int FinishTime; //完成時間
12 
13 int TurnoverTime; //周轉時間
14 
15 double WeightedTurnoverTime; //帶權周轉時間
16 
17 };

 

 

  進程就緒隊列

  采用STL中的隊列設置3個隊列,queue<PCB> Ready[3];

  時間片由數組timeslice[3]表示,大小分別為2,4,8。

 

  函數模塊

  主函數模塊分為3個模塊:讀入數據函數,多級反饋調度函數,輸出函數。

  

  3.流程圖

         

 

 

    4.代碼實現

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <iomanip>
  4 #include <vector>
  5 #include <queue>
  6 using namespace std;
  7  
  8 //作業結構體
  9 typedef struct PCB
 10 {
 11     int ID;                            //標識符
 12     int ComeTime;                    //到達時間
 13     int ServerTime;                    //服務時間
 14     int FinishTime;                    //完成時間
 15     int TurnoverTime;                //周轉時間
 16     double WeightedTurnoverTime;    //帶權周轉時間
 17 }PCB;
 18 const int QueueNum = 3;//就緒隊列長度     
 19 int timeslice[QueueNum];//第一個時間片 
 20 
 21 
 22  
 23 //輸入作業信息
 24 void InputPCB(vector<PCB> &PCBList, int xlice[])
 25 {
 26     
 27     cout << "輸入3個時間片大小: "<<endl;
 28     for(int i=0;i<3;i++){
 29         cin >> timeslice[i];
 30     } 
 31     
 32     while(1) {
 33         PCB temp;
 34         cout << "輸入標識符   "<<"到達時間    "<<"服務時間 "<<endl;
 35         cin >> temp.ID>> temp.ComeTime>> temp.ServerTime;
 36         temp.FinishTime = 0;        //暫時存放運行了多少時間,來判斷此作業是否運行結束
 37         PCBList.push_back(temp);
 38          cout<<"繼續?Y/N:"<<endl;
 39         char n;
 40         cin>>n;
 41         if(n=='Y'||n=='y')
 42         continue;
 43         else 
 44         break; 
 45         
 46     }
 47 }
 48  
 49  
 50  bool CmpByComeTime(const PCB &p1, const PCB &p2)
 51 {
 52     return p1.ComeTime < p2.ComeTime;
 53 }
 54 
 55  
 56 //MFQ算法
 57 void MFQ(vector<PCB> &PCBList, int timeslice[])
 58 {
 59     sort(PCBList.begin(), PCBList.end(), CmpByComeTime);        //按到達時間排序
 60     vector<PCB> result;    //保存結果
 61     int BeginTime = (*PCBList.begin()).ComeTime;                    //第一個作業開始時間
 62     queue<PCB> Ready[QueueNum];        //設置3個就緒隊列
 63     Ready[0].push(*PCBList.begin());
 64     PCBList.erase(PCBList.begin());
 65     cout<<"當前時刻:"<<BeginTime<<"   當前就緒隊列:"<<0<<endl;
 66     cout<<"第一個進程進入就緒隊列0"<<endl;
 67     cout<<endl;                
 68     while (!PCBList.empty())//進程數組不空 
 69     {
 70             //這段是為了防止前面的進程運行完了,后面的進程還沒到,造成死循環
 71         bool flag = false;
 72         for (int i = 0; i < QueueNum; ++i)
 73         {
 74             if (!Ready[i].empty())
 75             {
 76                 flag = true;
 77                 break;
 78             }
 79         }
 80         if(!flag)
 81         {
 82             Ready[0].push(*PCBList.begin());
 83             PCBList.erase(PCBList.begin());
 84             BeginTime = Ready[0].front().ComeTime;
 85         }
 86  
 87         for (int i = 0; i < QueueNum; ++i)
 88         { 
 89         
 90             if (i != QueueNum - 1)        //不是最后一個隊列
 91             {
 92                 while (!Ready[i].empty())    //當前隊列不空
 93                 {
 94                     if (!PCBList.empty() && BeginTime>= (*PCBList.begin()).ComeTime)    //有新作業到達,加入就緒隊列,轉到第一隊列
 95                     {
 96                         cout<<"當前時刻:"<<BeginTime<<endl;
 97                         cout<<"新進程"<<(*PCBList.begin()).ID<<"到達,將其放在第一隊列尾部"<<endl;
 98                         cout<<endl;     
 99                         Ready[0].push(*PCBList.begin());
100                         PCBList.erase(PCBList.begin());
101                         i = 0; 
102                         
103                         continue;
104                     }
105  
106                     if (Ready[i].front().FinishTime + timeslice[i] < Ready[i].front().ServerTime)        //時間片用完沒運行完,加入下一隊列隊尾
107                     {
108                         cout<<"當前時刻:"<<BeginTime+ timeslice[i]<<"   當前就緒隊列:"<<i<<endl;
109                         cout<<"當前進程"<<Ready[i].front().ID<<"在時間片內沒有運行完,加入下一個隊列尾部!"<<endl; 
110                         cout<<endl;    
111                         
112                         Ready[i].front().FinishTime += timeslice[i] ;
113                         Ready[i + 1].push(Ready[i].front());//加入下一個隊列 
114                         Ready[i].pop();
115                         BeginTime +=  timeslice[i] ;
116                     }
117                     else        //此作業運行完
118                     {   
119                         BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
120                         Ready[i].front().FinishTime = BeginTime;
121                         Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
122                         Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;
123                          cout<<"當前時刻:"<<BeginTime<<"   當前就緒隊列:"<<i<<endl;
124                          cout<<"當前進程"<<    Ready[i].front().ID<<"在時間片內運行完!"<<endl;
125                          cout<<endl;    
126                         //從就緒隊列中移除作業
127                         result.push_back(Ready[i].front());
128                         Ready[i].pop();
129                     }
130                 }
131             }
132             else
133             {
134                 while (!Ready[i].empty())
135                 {
136                     if (!PCBList.empty() && BeginTime >= (*PCBList.begin()).ComeTime)    //有新作業到達,加入就緒隊列,轉到第一隊列
137                     {
138                         cout<<"當前時刻:"<<BeginTime<<endl;
139                         cout<<"新進程"<<(*PCBList.begin()).ID<<"到達,將其放在最后隊列尾部"<<endl; 
140                         cout<<endl;    
141                         Ready[0].push(*PCBList.begin());
142                         PCBList.erase(PCBList.begin());
143                         i = -1;
144                         break;
145                     }
146                     if (Ready[i].front().FinishTime + timeslice[i]  < Ready[i].front().ServerTime)        //時間片用完沒運行完,加入隊尾
147                     {   cout<<"當前時刻:"<<BeginTime+ timeslice[i]<<"   當前就緒隊列:"<<i<<endl;
148                         cout<<"當前進程"<<Ready[i].front().ID<<"在時間片內沒有運行完,加入該隊列尾部!"<<endl; 
149                         cout<<endl;    
150                         Ready[i].front().FinishTime += timeslice[i] ;
151                         Ready[i].push(Ready[i].front());
152                         Ready[i].pop();
153                         BeginTime +=  timeslice[i] ;
154                     }
155                     else        //此作業運行完
156                     {
157                         BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
158                         Ready[i].front().FinishTime = BeginTime;
159                         Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
160                         Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;
161                          cout<<"當前時刻:"<<BeginTime<<"   當前就緒隊列:"<<i<<endl;
162                         cout<<"當前進程"<<    Ready[i].front().ID<<"在時間片內運行完!"<<endl;
163                         cout<<endl;    
164                         //從就緒隊列中移除作業
165                         result.push_back(Ready[i].front());
166                         Ready[i].pop();
167                     }
168                 }
169             }
170         }
171     }
172  
173     //按ComeTime升序排序,便於顯示結果
174     PCBList = result;
175     sort(PCBList.begin(), PCBList.end(), CmpByComeTime);
176 }
177  
178 //顯示結果
179 void show(vector<PCB> &PCBList)
180 {
181     int SumTurnoverTime = 0;
182     double SumWeightedTurnoverTime = 0;
183  
184     cout<<"標識符     "<<"達到時間    "<<"服務時間    "<<"完成時間    "<<"周轉時間    "<<"帶權周轉時間" <<endl;
185     
186     for (vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it){
187         cout<<(*it).ID<<"          "<<(*it).ComeTime<<"            "<< (*it).ServerTime<<"            "<<(*it).FinishTime<<"            "<<(*it).TurnoverTime<<"           "<< (*it).WeightedTurnoverTime<<endl;
188         SumTurnoverTime+=(*it).TurnoverTime;
189         SumWeightedTurnoverTime+=(*it).WeightedTurnoverTime;
190     }
191     
192     cout << "平均周轉時間: " << (double)SumTurnoverTime / PCBList.size() << endl;
193     cout << "平均帶權周轉時間: " << SumWeightedTurnoverTime / PCBList.size() << endl;
194 }
195  
196 //比較函數,按ComeTime升序排列
197 
198 
199  
200 int main()
201 {
202     vector<PCB> PCBList;//動態數組存放進程 
203 
204     InputPCB(PCBList, timeslice);//輸入時間片大小,作業信息
205  
206     MFQ(PCBList, timeslice);
207  
208     show(PCBList);//顯示結果
209  
210     return 0;
211 }
212  

    

      5.實例測試

 

 

 

結果分析:

如圖5所示,0時刻,1進程到達,運行1個時間片2,此時進程沒有運行完,加入下一隊列,進程2到達,轉到隊列0調度進程2,運行1個時間片2,進入隊列1隊尾等待。

時刻4開始,第一隊列為空,此時調度第二隊列,在進程1運行1個時間片4,沒有運行完,加入隊列2。

時刻8,進程3到達,加入到第一隊列尾部,調度進程3,進程3運行1個時間片2之后,加入下一隊列。

時刻10,隊列1中進程2開始運行,時刻12運行結束。刪除進程2.進程3開始運行,當前時間片內運行不完,加到隊列2隊尾。

時刻16,進入隊列2,調度進程1進行運行,時刻20,進程1運行結束,刪除進程1。運行進程3,在當前時間片下不能運行完,則加入隊列2。

時刻28,進入隊列2,調度進程3,時刻29運行完畢。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com