(一) 实验目的
进程是操作系统中最基本、最重要的概念,进程调度又是操作系统的核心模块。本实验要求学生独立地用C 或 C++语言编写一个简单的进程管理程序,其主要部分是进程调度。调度算法可由学生自行选择,如基于动态优先级的调度算法或多级反馈队列调度算法。
通过本实验可加深学生对进程各种状态的转化和各种调度算法的理解,提高系统程序设计能力。
(二) 实验题目
以链式结构组成空闲 PCB 栈,以双向链式结构组成进程的就绪队列和睡眠队列,模拟 UNIX的进程管理程序,实现以下操作(可用键盘命令或由产生的随机数决定操作和参数)。
1.创建一个新进程:如pid=newp(pri,size,time),申请空闲PCB和所需内存,填写PCB
的各项初始数据,将该 PCB 送入就绪队列。
2.调度和执行:自己设计优先调度算法,在就绪队列中选择一个优先级最高的进程,使其运行若干个单位时间。要求在运行期间进程的p_cpu、p_pri 和 p_time 要变化,并在适当的时机重新调度。
3.进程睡眠:进程运行时可调用自编的睡眠函数,主动进入睡眠状态,并转调度程序。也可由操作使进程强迫挂起,睡眠适当时间。进程睡眠时要在PCB 中记录睡眠原因和优先数。
4.进程的唤醒:根据睡眠原因,将相应的进程从睡眠队列中调出,转入就绪队列。如该进程优先级比现运行进程优先级高,转调度程序。
5.进程的终止:如一个进程运行完作业所需的时间,或者用操作杀死该进程,该进程就终止,释放所占用的内存和 PCB 资源,转调度程序。
(三)主要数据结构
每一个进程用一个进程控制块 PCB 表示,参考的 proc 结构定义如下:
struct proc { |
|
|
char | p_pid; | 进程标识数 |
char | p_pstat; | 进程状态 |
caddr_t p_addr; | 进程图象在内存中首址 | |
int | p_size; | 进程图象的长度 |
char | p_pri; | 进程优先数 |
char | p_cpu; | 进程当前运行的时间 |
int | p_time; | 作业运行的(剩余)总时间 |
char | p_wchan; | 进程睡眠原因 |
structproc *p_next, *p_prior; 进程 proc 的双向链指针
}
系统中有一个全局变量 curproc 指向现运行进程,还要定义几个队列的首指针。
(四)实验过程
1. 实验进程调度算法:
(1)动态优先权:当前运行进程用完时间片后,其优先权减去一个常数。
(2)轮转调度:每个个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。
2. 实验程序框图:
(1)轮询调度:
(2)动态优先级调度
3. 实验代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <ctime>
using namespace std;
//优先权法pcb
class PCB//类定义PCB表,适用于优先数
{
public:
int ID;
int priority;
int CPUtime;//runnedtime
int ALLtime;//needtime
int State;//1ready 2runing 3finish
int flag;//flag=1 finished
void set_PCB(int a,int b,int c,int d, inte,int f)
{
ID=a;
priority = b;
CPUtime=c;
ALLtime=d;
State=e;
flag=f;
}
};
//轮转法pcb
class PCB2
{
public:
int ID;
int CPUtime;
int ALLtime;
int State;
int flag;
void set_PCB2(int a,int b,int c,int d, inte)
{
ID=a;
CPUtime=b;
ALLtime=c;
State=d;
flag=e;
}
};
boolpriority_sort_higher(const PCB &m, const PCB &n)//sort函数,定义按优先数排序,当优先数相同时按序号排序(即先进先出)/priority high idsmall
{
if(m.priority == n.priority) return m.ID< n.ID;
return m.priority > n.priority;
}
void priority_way(vector<PCB> &pcb, vector<PCB> &wait,int pcbnum)//优先数算法
{
vector<PCB>::iterator it1;
it1 = pcb.begin();
int flag = pcbnum;
while(flag)
{
wait.erase(wait.begin());
(*it1).State = 2;
(*it1).priority -= 3;
(*it1).CPUtime += 1;
(*it1).ALLtime -= 1;
if((*it1).ALLtime == 0)
{
flag -= 1;
(*it1).flag =1;
cout<<left<<setw(10)<<(*it1).ID<<setw(10)<<(*it1).State<<setw(10)<<(*it1).priority<<setw(10)<<(*it1).CPUtime<<setw(10)<<(*it1).ALLtime<<setw(10)<<(*it1).flag<<endl;
pcb.erase(pcb.begin());
sort(wait.begin(), wait.end(),priority_sort_higher);
sort(pcb.begin(), pcb.end(),priority_sort_higher);
}
else
{
cout<<left<<setw(10)<<(*it1).ID<<setw(10)<<(*it1).State<<setw(10)<<(*it1).priority<<setw(10)<<(*it1).CPUtime<<setw(10)<<(*it1).ALLtime<<setw(10)<<(*it1).flag<<endl;
(*it1).State = 1;
wait.push_back(*it1);
sort(wait.begin(),wait.end(),priority_sort_higher);
sort(pcb.begin(),pcb.end(),priority_sort_higher);
}
}
}
void round_robin_way(vector<PCB2> &pcb2,vector<PCB2> &wait2)//时间片,every 2
{
vector<PCB2>::iterator it2;
it2 = wait2.begin();
int flag=5;
while(flag)
{
it2 = pcb2.begin();
wait2.erase(wait2.begin());//出队(等待队列)
(*it2).State = 2;
if((*it2).ALLtime==1)
{
(*it2).CPUtime +=1;
(*it2).ALLtime -=1;
flag -= 1;
(*it2).flag = 1;
cout << left <<setw(10) << (*it2).ID << setw(10) <<(*it2).State<<setw(10)<<(*it2).CPUtime<<setw(10)<<(*it2).ALLtime<<setw(10)<<(*it2).flag<<endl;
pcb2.erase(pcb2.begin());
continue;
}
else if((*it2).ALLtime==2)
{
(*it2).CPUtime +=2;
(*it2).ALLtime -=2;
flag-=1;
(*it2).flag =1;
cout<<left<<setw(10)<<(*it2).ID<<setw(10)<<(*it2).State<<setw(10)<<(*it2).CPUtime<<setw(10)<<(*it2).ALLtime<<setw(10)<<(*it2).flag<<endl;
pcb2.erase(pcb2.begin());
continue;
}
else
{
(*it2).State = 2;
(*it2).CPUtime +=2;
(*it2).ALLtime -=2;
cout<<left<<setw(10)<<(*it2).ID<<setw(10)<<(*it2).State<<setw(10)<<(*it2).CPUtime<<setw(10)<<(*it2).ALLtime<<setw(10)<<(*it2).flag<<endl;
(*it2).State = 2;
wait2.push_back(*it2);
PCB2 q = *it2;
pcb2.erase(pcb2.begin());
pcb2.push_back(q);
}
}
}
int random(int start, int end)
{
return start+(end-start)*rand()/(RAND_MAX +1.0);
}
int main( )
{
cout<<"-------------------------------模拟进程调度----------------------------------"<<endl;
srand(unsigned(time(0)));
int flag_0;
cout<<"请输入想要模拟进程调度算法的编号"<<endl;
cout<<"1.优先数调度;2.时间片轮转调度。"<<endl;
cin>>flag_0;
int pcbnum=0;
cout<<"创建进程数量:";
cin>>pcbnum;
int pro,time;
if(flag_0 == 1)
{
vector<PCB> pcb;
cout<<"创建"<<pcbnum<<"个进程,即将设置随机优先数与运行时间(优先数越大优先级越高)"<<endl;
for( int i = 1; i <= pcbnum; i++)
{
pro=random(1,30);
time=random(1,20);
PCB q;
q.set_PCB(i,pro,0,time,1,0);
cout<<"id:"<<i<<""<<"priority:"<<pro<<""<<"Alltime:"<<time<<endl;
pcb.push_back(q);
}
sort(pcb.begin(),pcb.end(),priority_sort_higher);//按优先数排序,利用sort函数
vector<PCB> wait(pcbnum);
copy(pcb.begin(),pcb.end(),back_inserter(wait));
cout<<"该进程运行情况如下(flag=0代表未完成,flag=1代表已完成)"<<endl;
cout<<left<<setw(10)<<"ID"<<setw(10)<<"State"<<setw(10)<<"priority"<<setw(10)<<"CPUtime"<<setw(10)<<"ALLtime"<<setw(10)<<"flag1" << endl;
priority_way(pcb,wait,pcbnum);
}
else if(flag_0 ==2)
{
vector <PCB2> pcb2;
vector<PCB2>::iterator it2;
it2 = pcb2.begin();
cout<<"创建"<<pcbnum<<"个进程,即将设置随机优先数与运行时间(优先数越大优先级越高)"<<endl;
for(int i = 1; i <= 5; i++)
{
time=random(1,20);
PCB2 q2;
q2.set_PCB2(i,0,time,1,0);
cout<<"id:"<<i<<""<<"Alltime:"<<time<<endl;
pcb2.push_back(q2);
}
vector<PCB2> wait2(pcbnum);
copy(pcb2.begin(),pcb2.end(),back_inserter(wait2));
cout<<"该进程运行情况如下(flag=0代表未完成,flag=1代表已完成)"<<endl;
cout <<left<<setw(10)<<"ID"<<setw(10)<<"State"<<setw(10)<<"CPUtime"<<setw(10)<<"ALLtime"<<setw(10)<<"flag1" << endl;
round_robin_way(pcb2, wait2);
}
cout<<"----------------------------------END--------------------------------------"<<endl;
return 0;
}
4. 实验结果
(1)优先数调度:
(2)轮询调度:
(五)实验总结:
通过这次实验,我采用的是两种进程调度算法对四个进程进行调度,每个进程可有三个状态,并假设初始状态为就绪状态。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的优先数或轮转时间数以及进程需运行的时间片数的初始值均由用户给定。在优先数算法中,进程每执行一次,优先数减3,CPU时间片数加1,进程还需要的时间片数减1。在轮转算法中,采用固定时间片(即:每执行一次进程,该进程的执行时间片数为已执行了2个单位),这时,CPU时间片数加2,进程还需要的时间片数减2,并排列到就绪队列的队尾上。 对于遇到优先数一致的情况,采用FIFO策略解决。
通过这次实验,对进程调度有深入的了解,在实验过程中遇到了很多问题,但是通过和同学请教,以及在网上查找有关资料,最终完成了本次实验要求。