- 原理介紹
- 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運行完畢。