优先权法与轮转法
主要实现进程调度里的优先权法和轮转法。
流程图为:
分析
用户可以通过输入数字来控制进程的数目以及本次调度使用的方法。进程的创建及优先权、所需时间均由随机数生成,轮转法优先权初始化均为一个相同的常量。
就绪队列:这里我用一个优先队列实现,由于需要适应两种方法,我设定队列排序的规则是,优先权不一致时优先权大者排在前面,一致时pid小者排在前面。
优先权法:每次调度选取就绪队列的队首并pop,将其还需的时间减一,优先权减三,若进程运行结束(即不需要CPU运行时间了),将其插入结束动态数组中,否则再插回就绪队列中,打印当前所有进程状态,调至下一次调度。
轮转法:通过随机数产生每次调度每个进程可用的时间片的值,这里因为就绪队列的设计时已经考虑到这个方法,所以每次调度时可以直接选择队首进程并pop,每个时间小片结束判断该进程是否结束,若结束,将其插入结束动态数组中,否则再插回就绪队列中,这里与优先权法设计的不同的是,未修改优先权值,而是在这次分配给该进程的所有时间片耗尽后将优先权值减少一个固定的常数并插回就绪队列中,这样可以保证所有时间片是轮转的。
完整代码
#include<iostream>
#include<stdio.h>
#include<cstdlib>
#include<queue>
#include<vector>
#include<time.h>
using namespace std;
struct thread{
int pid,priority,time;
bool operator <(const thread &b) const{
return priority==b.priority?pid>b.pid:priority<b.priority;
}
};
priority_queue<thread> pq;
vector<thread> v;
void print(){
printf("目前结束运行的进程:\n");
if(v.size()==0) printf("无\n");
for(int i=0;i<v.size();i++){
printf("pid为%d的进程\n",v[i].pid);
}
priority_queue<thread> now=pq;
printf("目前为就绪态的进程:\n");
if(now.empty()) printf("无\n");
while(!now.empty()){
thread top=now.top();
now.pop();
printf("pid为%d的进程: 目前优先级为%d, 还需要CPU时间为%d\n",top.pid,top.priority,top.time);
}
cout<<endl;
}
int main(){
int n,mode;
cout<<"请选择进程调度方法,输入1选择优先权法,输入2选择轮转法:";
cin>>mode;
while(1){
if(mode==1){
printf("已选择优先权法\n");
break;
}
else if(mode==2){
printf("已选择轮转法\n");
break;
}
else{
printf("Error!请重新选择:");
cin>>mode;
}
}
cout<<"请输入进程数:";
cin>>n;
srand((unsigned)time(NULL));
for(int i=1;i<=n;i++){
thread now={i,mode==1?rand()%100+1:10000,rand()%20+1};
printf("创建第%d个进程: 目前优先级为%d,需要的CPU时间为%d\n",i,now.priority,now.time);
pq.push(now);
}
printf("已创建%d个进程并已放入就绪队列\n",n);
printf("开始调度\n");
int m=rand()%5+1,time=0;
while(!pq.empty()){
thread top=pq.top();
printf("本次调度选用pid为%d的进程\n",top.pid);
pq.pop();
top.time--;
if(mode==1) top.priority-=3;
else time++;
if(top.time==0) v.push_back(top);
else{
if(mode==2&&time==m){
printf("本轮pid为%d的进程拥有的时间片耗尽\n\n",top.pid);
time=0;
top.priority-=m;
}
pq.push(top);
}
print();
}
printf("所有进程已完成!\n");
return 0;
}
运行情况
优先权法测试:
进程顺利运行结束:
轮转法测试:
所有进程顺利结束:
体会
我学习了进程调度的两种方法:优先权法和轮转法。通过自己手动设计并实现进程调度的全过程,让我更是印象深刻。
而在实现的过程中,我也经常出现一些问题:
① 一次调度运行后的进程怎么修改,怎么再插回去
② 就绪队列的设计中一个进程的排序优先怎么定义
③ 怎么把一个优先队列里的所有元素打印出来
虽然最后大部分问题都得到了解决,但确实还存在很多冗余或者不是很完善的地方需要进行改正。