調度的基本概念:從就緒隊列中按照一定的算法選擇一個進程並將處理機分配給它運行,以實現進程並發地執行。
進程信息
1 struct node { 2 string name;//進程名稱 3 int id;//進程id 4 int time;//進程服務時間 5 int rtime;//進程服務時間(主要用於時間片輪轉算法) 6 int level;//進程優先級 7 int start;//進程提交時間 8 int lst;//進程調度時間 9 };
1 set<string> pname;//存放進程名稱,防止創建重復進程 2 queue<node> qq;//時間片輪轉時用到的就緒隊列 3 queue<node> pp;//進程的執行隊列 4 queue<node> db;//時間片算法中的調度順序 5 priority_queue<node, vector<node>, cmpspf> spf;//短時間優先算法隊列 6 priority_queue<node, vector<node>, cmpfpf> fpf;//優先級算法隊列 7 vector<node> ready;//就緒隊列 8 vector<node> emy;//已刪除的進程
用vector容器存放就緒的進程(每插入一個,sort一下,依據進程提交時間升序排列)
spf(短作業優先算法)
算法思想:服務時間短的進程在就緒隊列前面。
算法規則:要求服務時間最短的進程/作業優先得到服務。
算法實現:模擬時間,將已提交的進程插入優先隊列,在依據時間是否到達完成時間來判斷哪個進程被移入內存中運行
代碼:
1 struct cmpspf { 2 bool operator() (node a, node b) { 3 if (a.time == b.time)return a.start > b.start; 4 return a.time > b.time; 5 } 6 }; 7 8 int j = 0, num = ready.size(),ok=1; 9 sum = -1, ans = 0, avg = 0.00; 10 //sum作為在執行進程的完成時間 11 if (t == 1) { 12 for(int i=0;i<=100000;i++) { 13 if (i == sum) {//首先判斷是否到達在執行進程的完成時間 14 node temp; 15 temp = spf.top(); spf.pop(); 16 temp.lst = i - temp.start;//計算周轉時間 17 ans += temp.lst;//總的周轉時間 18 avg += double(temp.lst) / double(temp.time);//總的帶權周轉時間 19 pp.push(temp);//執行完畢的進程放入執行隊列 20 if (!spf.empty())sum += spf.top().time; 21 } 22 while (j < num && i == ready[j].start) {//將到達進程提交時間的進程放入就緒隊列 23 spf.push(ready[j]); 24 //當CPU執行過程中出現空閑時,更新sum值 25 if (i > sum&&sum<=spf.top().start)sum = spf.top().start + spf.top().time; 26 j++; 27 } 28 if (ok&&!spf.empty()) {//第一個執行的進程的完成時間 29 sum = i + spf.top().time; 30 ok = 0; 31 } 32 if (j == num && spf.empty())break;//所有進程執行完畢 33 }
34 printf("進程 周轉時間 帶權周轉時間\n"); 35 while (!pp.empty()) { 36 node out; 37 out = pp.front(); pp.pop(); 38 cout << out.name; 39 printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time)); 40 } 41 printf("平均周轉時間為:%.2f\n", double(ans) / double(num)); 42 printf("平均帶權周轉時間為%.2f\n", avg);
fpf(優先級調度算法)
算法思想:進程優先級高的進程在就緒隊列前面。
算法規則:要求進程優先級高的進程/作業優先得到服務。
算法實現:模擬時間,將已提交的進程插入優先隊列,在依據時間是否到達完成時間來判斷哪個進程被移入內存中運行
代碼:邏輯跟spf算法是一樣的這里不過多敘述。
1 //spf、fpf的區別就在於優先隊列中的規則不同 2 struct cmpfpf { 3 bool operator() (node a, node b) { 4 if (a.level == b.level)return a.start > b.start; 5 return a.level < b.level; 6 } 7 };
for(int i=0;i<=10000;i++) { if (i == sum) { node temp; temp = fpf.top(); fpf.pop(); temp.lst = i - temp.start; ans += temp.lst; avg += double(temp.lst) / double(temp.time); pp.push(temp); if (!fpf.empty())sum += fpf.top().time; } while (j < num && i == ready[j].start) { fpf.push(ready[j]); if (i > sum&&sum<=fpf.top().start)sum = fpf.top().start + fpf.top().time; j++; } if (ok&&!fpf.empty()) { sum = i + fpf.top().time; ok = 0; } if (j == num && fpf.empty())break; } printf("進程 周轉時間 帶權周轉時間\n"); while (!pp.empty()) { node out; out = pp.front(); pp.pop(); cout << out.name; printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time)); } printf("平均周轉時間為:%.2f\n", double(ans) /double(num)); printf("平均帶權周轉時間為%.2f\n", avg);
時間片輪轉算法
算法思想:公平的、輪流的為各個進程服務,讓每個進程在一定時間間隔內都可以得到響應
算法規則:系統根據FCFS策略,將所有的就緒進程排成一個就緒隊列。
輪流讓各個進程執行一個時間片的,若進程未在一個時間片內執行完,則被剝奪處理機,將進程放到就緒隊列隊尾重新排隊。
算法實現:利用隊列模擬就緒隊列,模擬時間,每次時間增加一個時間片長度,先判斷是否有進程在時間片內結束,如果有的話,就對時間進行修改回退到剛完成進程的時間,再判斷時間片內是否有進程提交,有的話加入隊列。
代碼
1 printf("請設置時間片大小:\n"); 2 sf(m); 3 for (int i = 0; i <= 100000; i += m) {//每次自增一個時間片 4 if (!qq.empty()) {//當運行隊列有進程時,則運行該進程 5 node temp; 6 temp = qq.front(); qq.pop(); 7 db.push(temp); 8 if (temp.time > m) {//若進程不能在該時間片內運行完畢,則將服務時間減去時間片,再重新放入隊列,這也是使用rtime計算帶權周轉時間的原因 9 temp.time -= m; 10 qq.push(temp); 11 } 12 else {//反之回退時間,並將已完成的進程放入執行完畢隊列 13 i =i- m + temp.time; 14 temp.lst = i - temp.start; 15 ans += temp.lst; 16 pp.push(temp); 17 } 18 } 19 while (j < num && i >= ready[j].start) {//到達時間片的進程放入隊列 20 if (ok||qq.empty()) { 21 i = ready[j].start; 22 ok = 0; 23 } 24 ready[j].rtime = ready[j].time; 25 qq.push(ready[j]); 26 j++; 27 } 28 if (j == num && qq.empty())break; 29 } 30 printf("進程調度順序:\n"); 31 while(!db.empty()){cout<<db.front().name<<" ";db.pop();} 32 printf("\n進程執行完畢順序 周轉時間 帶權周轉時間\n"); 33 while (!pp.empty()) { 34 node out; 35 out = pp.front(); pp.pop(); 36 cout << out.name; 37 printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.rtime)); 38 avg += double(out.lst) / double(out.rtime); 39 } 40 printf("平均周轉時間%.2f\n", double(ans) / double(num)); 41 printf("平均帶權周轉時間為%.2f\n", avg/double(num));
總代碼如下:

1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 typedef vector<int> vi; 5 typedef pair<int, int> ii; 6 #define inf 1e9 7 #define F first 8 #define S second 9 #define dbg(x) cout<<#x<<" value : "<<x<<"\n"; 10 #define rep(i,j,k) for(int i = (j); i <= (k); i++) 11 #define rep__(i,j,k) for(int i = (j); i < (k); i++) 12 #define per(i,j,k) for(int i = (j); i >= (k); i--) 13 #define per__(i,j,k) for(int i = (j); i > (k); i--) 14 #define mst(a,b) memset(a,b,sizeof(a)) 15 #define sf(n) scanf_s("%d",&n) 16 #define stf(n,m) scanf("%d%d",&n,&m) 17 #define pf(n) printf("%d\n",n) 18 #define slf(n) scanf("%lld",&n) 19 #define plf(n) printf("%lld\n",n) 20 const int N = 1e3 + 10; 21 priority_queue<int, vector<int>, less<int> > q; 22 int t, x, sum, ans, m; 23 double avg; 24 string k; 25 struct node { 26 string name;//進程名稱 27 int id;//進程id 28 int time;//進程服務時間 29 int rtime;//進程服務時間(主要用於時間片輪轉算法) 30 int level;//進程優先級 31 int start;//進程提交時間 32 int lst;//進程調度時間 33 }; 34 struct cmpspf { 35 bool operator() (node a, node b) { 36 if (a.time == b.time)return a.start > b.start; 37 return a.time > b.time; 38 } 39 }; 40 struct cmpfpf { 41 bool operator() (node a, node b) { 42 if (a.level == b.level)return a.start > b.start; 43 return a.level < b.level; 44 } 45 }; 46 set<string> pname;//存放進程名稱,防止創建重復進程 47 queue<node> qq;//時間片輪轉時用到的就緒隊列 48 queue<node> pp;//進程的執行隊列 49 queue<node> db;//時間片算法中的調度順序 50 priority_queue<node, vector<node>, cmpspf> spf;//短時間優先算法隊列 51 priority_queue<node, vector<node>, cmpfpf> fpf;//優先級算法隊列 52 vector<node> ready;//就緒隊列 53 vector<node> emy;//已刪除的進程 54 bool cmp(const node& a, const node& b) { 55 return a.start < b.start; 56 } 57 void create() { 58 node a; 59 printf("請輸入新進程的名稱:\n"); 60 cin >> a.name; 61 if (pname.find(a.name) != pname.end()) { 62 printf("進程已存在,請從新輸入:\n"); 63 create(); 64 return; 65 } 66 pname.insert(a.name); 67 printf("請輸入新進程的到達時間、服務時間:\n"); 68 sf(a.start);sf(a.time); 69 printf("請輸入新進程的PID:\n");sf(a.id); 70 printf("請輸入新進程的優先級:\n");sf(a.level); 71 ready.push_back(a); 72 sort(ready.begin(), ready.end(), cmp); 73 } 74 void kill() { 75 node b; 76 printf("請輸入要終止的進程名字\n"); 77 cin >> k; 78 if (pname.find(k) != pname.end()) { 79 int num = ready.size(); 80 for (int i = 0; i < num; i++) { 81 if (ready[i].name == k) { 82 b = ready[i]; 83 emy.push_back(b); 84 ready.erase(ready.begin() + i); 85 printf("終止進程成功!\n"); 86 } 87 if (num == ready.size()) { 88 printf("該進程已在空隊列中!\n"); 89 } 90 } 91 } 92 else { 93 printf("該進程不存在,請輸入正確的進程名!\n"); 94 kill(); 95 return; 96 } 97 } 98 void display() { 99 while (!pp.empty())pp.pop(); 100 while (!spf.empty())spf.pop(); 101 while (!fpf.empty())fpf.pop(); 102 while (!qq.empty())qq.pop(); 103 if (ready.empty()) { 104 printf("就緒隊列為空!\n"); 105 return; 106 } 107 printf("請選擇調度算法\n"); 108 printf("1、spf調度算法\n"); 109 printf("2、fpf調度算法\n"); 110 printf("3、時間片輪轉算法\n"); 111 printf("4、返回菜單\n"); 112 sf(t); 113 int j = 0, num = ready.size(),ok=1; 114 sum = -1, ans = 0, avg = 0.00; 115 //sum作為在執行進程的完成時間 116 if (t == 1) { 117 rep(i, 0, 100000) { 118 if (i == sum) {//首先判斷是否到達在執行進程的完成時間 119 node temp; 120 temp = spf.top(); spf.pop(); 121 temp.lst = i - temp.start;//計算周轉時間 122 ans += temp.lst;//總的周轉時間 123 avg += double(temp.lst) / double(temp.time);//總的帶權周轉時間 124 pp.push(temp); 125 if (!spf.empty())sum += spf.top().time; 126 } 127 while (j < num && i == ready[j].start) {//將到達進程提交時間的進程放入就緒隊列 128 spf.push(ready[j]); 129 //當CPU執行過程中出現空閑時,更新sum值 130 if (i > sum&&sum<=spf.top().start)sum = spf.top().start + spf.top().time; 131 j++; 132 } 133 if (ok&&!spf.empty()) {//第一個執行的進程的完成時間 134 sum = i + spf.top().time; 135 ok = 0; 136 } 137 if (j == num && spf.empty())break;//所有進程執行完畢 138 } 139 printf("進程 周轉時間 帶權周轉時間\n"); 140 while (!pp.empty()) { 141 node out; 142 out = pp.front(); pp.pop(); 143 cout << out.name; 144 printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time)); 145 } 146 printf("平均周轉時間為:%.2f\n", double(ans) / double(num)); 147 printf("平均帶權周轉時間為%.2f\n", avg); 148 } 149 else if (t == 2) { 150 rep(i, 0, 100000) { 151 if (i == sum) { 152 node temp; 153 temp = fpf.top(); fpf.pop(); 154 temp.lst = i - temp.start; 155 ans += temp.lst; 156 avg += double(temp.lst) / double(temp.time); 157 pp.push(temp); 158 if (!fpf.empty())sum += fpf.top().time; 159 } 160 while (j < num && i == ready[j].start) { 161 fpf.push(ready[j]); 162 if (i > sum&&sum<=fpf.top().start)sum = fpf.top().start + fpf.top().time; 163 j++; 164 } 165 if (ok&&!fpf.empty()) { 166 sum = i + fpf.top().time; 167 ok = 0; 168 } 169 if (j == num && fpf.empty())break; 170 } 171 printf("進程 周轉時間 帶權周轉時間\n"); 172 while (!pp.empty()) { 173 node out; 174 out = pp.front(); pp.pop(); 175 cout << out.name; 176 printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time)); 177 } 178 printf("平均周轉時間為:%.2f\n", double(ans) / double(num)); 179 printf("平均帶權周轉時間為%.2f\n", avg); 180 } 181 else if (t == 3) { 182 printf("請設置時間片大小:\n"); 183 sf(m); 184 for (int i = 0; i <= 100000; i += m) {//每次自增一個時間片 185 if (!qq.empty()) {//當運行隊列有進程時,則運行該進程 186 node temp; 187 temp = qq.front(); qq.pop(); 188 db.push(temp); 189 if (temp.time > m) {//若進程不能在該時間片內運行完畢,則將服務時間減去時間片,再重新放入隊列,這也是使用rtime計算帶權周轉時間的原因 190 temp.time -= m; 191 qq.push(temp); 192 } 193 else {//反之回退時間,並將已完成的進程放入執行完畢隊列 194 i =i- m + temp.time; 195 temp.lst = i - temp.start; 196 ans += temp.lst; 197 pp.push(temp); 198 } 199 } 200 while (j < num && i >= ready[j].start) {//到達時間片的進程放入隊列 201 if (ok||qq.empty()) { 202 i = ready[j].start; 203 ok = 0; 204 } 205 ready[j].rtime = ready[j].time; 206 qq.push(ready[j]); 207 j++; 208 } 209 if (j == num && qq.empty())break; 210 } 211 printf("進程調度順序:\n"); 212 while (!db.empty()) { cout << db.front().name << " "; db.pop(); } 213 printf("\n進程執行完畢順序 周轉時間 帶權周轉時間\n"); 214 printf("進程 周轉時間 帶權周轉時間\n"); 215 while (!pp.empty()) { 216 node out; 217 out = pp.front(); pp.pop(); 218 cout << out.name; 219 printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.rtime)); 220 avg += double(out.lst) / double(out.rtime); 221 } 222 printf("平均周轉時間%.2f\n", double(ans) / double(num)); 223 printf("平均帶權周轉時間為%.2f\n", avg/double(num)); 224 } 225 else if (t == 4) { 226 return; 227 } 228 else { 229 printf("輸入有誤,請按照提示輸入:\n"); 230 display(); 231 return; 232 } 233 } 234 inline void meun() { 235 printf("******************菜單************************\n\n"); 236 printf("********** 1、輸入進程 ***************\n"); 237 printf("********** 2、輸出隊列 ***************\n"); 238 printf("********** 3、終止進程 ***************\n"); 239 printf("********** 4、退出程序 ***************\n"); 240 } 241 void solve() { 242 while (1) { 243 meun(); 244 sf(x); 245 switch (x) { 246 case 1: 247 create(); 248 break; 249 case 2: 250 display(); 251 break; 252 case 3: 253 kill(); 254 break; 255 case 4: 256 return; 257 default: 258 printf("請按照提示信息進行輸入\n"); 259 break; 260 } 261 } 262 return; 263 } 264 265 int main() 266 { 267 solve(); 268 return 0; 269 }
可以補充的地方,阻塞進程,加入新的vector,每阻塞一個進程,就將其在ready中刪除放入新的vector中,喚醒時在阻塞隊列中找到該進程,將其移回ready隊列。
其實代碼寫的不是很漂亮,懶省事用了stl,沒寫鏈表,時間也是模擬出來的跟真實情況有很大差別,實現的效率也不高(進程少了還行,多了就挺耗時間的,草率地說是O(log(n!)的算法)。這次代碼實現的三種算法都是非搶占式的算法,實際情況要比這復雜的多,代碼僅供參考,歡迎大家提意見。
優點就是容易想,算是非常暴力的模擬了;能隨便加進程,不斷更新調度順序。以后看情況會把程序給完善完善。