进程调度算法spf,fpf,时间片轮转算法实现

最后都变了- 提交于 2019-12-05 02:38:24

调度的基本概念:从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程并发地执行。

进程信息

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 }
View Code

可以补充的地方,阻塞进程,加入新的vector,每阻塞一个进程,就将其在ready中删除放入新的vector中,唤醒时在阻塞队列中找到该进程,将其移回ready队列。

其实代码写的不是很漂亮,懒省事用了stl,没写链表,时间也是模拟出来的跟真实情况有很大差别,实现的效率也不高(进程少了还行,多了就挺耗时间的,草率地说是O(log(n!)的算法)。这次代码实现的三种算法都是非抢占式的算法,实际情况要比这复杂的多,代码仅供参考,欢迎大家提意见。

优点就是容易想,算是非常暴力的模拟了;能随便加进程,不断更新调度顺序。以后看情况会把程序给完善完善。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!