实验二 进程调度的设计与实现.docx
《实验二 进程调度的设计与实现.docx》由会员分享,可在线阅读,更多相关《实验二 进程调度的设计与实现.docx(18页珍藏版)》请在冰豆网上搜索。
实验二进程调度的设计与实现
院系:
计算机学院
实验课程:
操作系统
实验项目:
进程调度的设计与实现
指导老师:
陈红英老师
开课时间:
2011~2012年度第2学期
专业:
网络工程
班级:
10级
学生:
yuth
学号:
*
一、实验项目名称
进程调度的设计与实现
二、实验目的及要求
1、综合应用下列知识点设计并实现操作系统的进程调度:
邻接表,布尔数组,非阻塞输入,图形用户界面GUI,进程控制块,进程状态转换,多级反馈队列进程调度算法。
2、加深理解操作系统进程调度的过程。
3、加深理解多级反馈队列进程调度算法。
三、实验主要硬件软件环境
32位PC机,VC++6
四、实验内容及步骤
1、采用一种熟悉的语言,如C、PASCAL或C++等,编制程序,最好关键代码采用C/C++,界面设计可采用其它自己喜欢的语言。
2、采用多级反馈队列调度算法进行进程调度。
3、每个进程对应一个PCB。
在PCB中包括进程标识符pid、进程的状态标识status、进程优先级priority、进程的队列指针next和表示进程生命周期的数据life(在实际系统中不包括该项)。
4、创建进程时即创建一个PCB,各个进程的pid都是唯一的,pid是在1到100范围内的一个整数。
可以创建一个下标为1到100的布尔数组,“真”表示下标对应的进程标识号是空闲的,“假”表示下标对应的进程标识号已分配给某个进程。
5、进程状态status的取值为“就绪ready”或“运行run”,刚创建时,状态为“ready”。
被进程调度程序选中后变为“run”。
6、进程优先级priority是0到49范围内的一个随机整数。
7、进程生命周期life是1到5范围内的一个随机整数。
8、初始化时,创建一个邻接表,包含50个就绪队列,各就绪队列的进程优先级priority分别是0到49。
9、为了模拟用户动态提交任务的过程,要求动态创建进程。
进入进程调度循环后,每次按ctrl+f即动态创建一个进程,然后将该PCB插入就绪队列中。
按ctrl+q退出进程调度循环。
10、在进程调度循环中,每次选择优先级最大的就绪进程来执行。
将其状态从就绪变为运行,通过延时一段时间来模拟该进程执行一个时间片的过程,然后优先级减半,生命周期减一。
设计图形用户界面GUI,在窗口中显示该进程和其他所有进程的PCB内容。
如果将该运行进程的生命周期不为0,则重新把它变为就绪状态,插入就绪队列中;否则该进程执行完成,撤消其PCB。
以上为一次进程调度循环。
五、实验设计
(一)、需求分析
1、采用一种熟悉的语言,如C、PASCAL或C++等,编制程序,最好关键代码采用C/C++,界面设计可采用其它自己喜欢的语言。
2、采用多级反馈队列调度算法进行进程调度。
3、要求动态创建进程。
进入进程调度循环后,每次按ctrl+f即动态创建一个进程,然后将该PCB插入就绪队列中。
按ctrl+q退出进程调度循环。
(二)详细设计
1、总体设计方案流程图
2、创建进程函数
3、进程调度函数
4、使用的数据结构
(一)、进程的PCB结构
//进程队列节点(由于仅仅是模拟实验,这里无动作)
structprocess
{
};
//进程控制块PCB
structPCB
{
intpid;//进程标识符
stringstatus;//进程的状态标识,取值为“就绪ready”或“运行run”
intpriority;//进程优先级,0到49范围内的一个随机整数。
process*next;//进程的队列指针
intlife;//进程生命周期,1到5范围内的一个随机整数。
voidoperator=(PCBp)//运算符=重载
{
pid=p.pid;
status=p.status;
priority=p.priority;
next=p.next;
life=p.life;
}
};
//就绪队列节点
structreadyque
{
PCBpc;
structreadyque*next;
voidoperator=(readyquer)//运算符=重载
{
pc=r.pc;
next=r.next;
}
};
(二)、进程调度类threadmanager
成员:
classthreadmanager
{
private:
boolpidarray[101];//“真”表示下标对应的进程标识号是空闲的,“假”表示下标对应的进程标识号已分配给某个进程。
structreadyqueadj[50];//邻接表
public:
threadmanager();//构造函数
voidrun();//运行进程调度程序(对外的接口)
boolnewpro();//新建一个进程的函数
voidManage_Draw();//进程调度并将进程调度的情况显示在屏幕上
voidDrawpro(intpriority);//画出优先级比正在运行进程优先级低的其他进程
};
六、主要功能模块
(一)、构造函数
threadmanager:
:
threadmanager()
{
inti;
//初始化邻接表
for(i=0;i<50;i++)
adj[i].next=NULL;
//“真”表示下标对应的进程标识号(1~100)是空闲的,“假”表示下标对应的进程标识号已分配给某个进程。
for(i=0;i<101;i++)
pidarray[i]=true;//刚开始每个进程标识号都是空闲的。
}
(二)、运行进程调度程序。
功能:
监听各个按键并作出相应动作
voidthreadmanager:
:
run()
{
intc;
srand((unsigned)time(NULL));//srand()函数产生一个以当前时间开始的随机种子
while
(1)
{
//cout<<"请输入要进行的操作:
Ctrl+f(新建进程)Ctrl+r(开始调度)Ctrl+q(停止调度)"<cout<<"Pleaseinputthekeyyouwanttodo"<cout<<"Ctrl+f(newthread),Ctrl+r(startmanager)Ctrl+q(stopmanager)"<//检查当前是否键盘输入,若有则返回一个非0值,否则返回0
if(!
_kbhit())
{
c=_getch();//_getch返回的是键的ascii
switch(c)
{
case0x6:
//Ctrl+f(新建进程)
srand((unsigned)time(NULL));//srand()函数产生一个以当前时间开始的随机种子
newpro();
break;
case0x12:
//Ctrl+r(开始调度)
Manage_Draw();
break;
case0x11:
//Ctrl+q(停止调度)
;
}
}
}
}
//进程调度并将进程调度的情况显示在屏幕上
voidthreadmanager:
:
Manage_Draw()
{
readyque*rq=NULL,*tmpr=NULL;
inti,j=0;
//cout<<"优先级标识符状态标识生命周期"<cout<<"prioritypidstatuslife"<j=1;
for(i=49;i>=0;i--)//找优先级最大的进程来执行
{
if(adj[i].next!
=NULL)//当对应的就绪队列不为空时
{
rq=adj[i].next;//从就绪队列取出一个进程执行。
adj[i].next=rq->next;
rq->pc.status="run";
Sleep(1500);//通过延时一段时间来模拟该进程执行一个时间片的过程.
//画优先级
cout<<"**"<pc.priority<<"**";
//画一次进程的调度情况
//1、画正在运行进程的PCB
//设置下一个输出文本的字体颜色:
绿色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
cout<<"--->**"<pc.pid<<"**"<pc.status<<"**"<pc.life<<"**";
//2、画优先级与正在运行进程相同的其他进程的PCB(如果有的话)
//设置下面输出文本的字体颜色:
白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
tmpr=adj[i].next;
while(tmpr!
=NULL)//当对应的就绪队列不为空时
{
cout<<"--->**"<pc.pid<<"**"<pc.status<<"**"<pc.life<<"**";
tmpr=tmpr->next;
j++;
if(j%3==0)
cout<}
cout<//3、画出优先级比正在运行进程优先级低的其他进程
Drawpro(i);
(rq->pc.priority)/=2;//优先级减半
(rq->pc.life)-=1;//生命周期减一
//如果该运行进程的生命周期不为0,则重新把它变为就绪状态,插入就绪队列中
if(rq->pc.life>0)
{
rq->pc.status="ready";
rq->next=adj[rq->pc.priority].next;
adj[rq->pc.priority].next=rq;
}
else//否则将其进程号归还。
pidarray[i]=true;
break;//一次进程调度循环结束。
}//endofif
}//endoffor
cout<<"onetimemanagerhavefinish!
"<}
//画出优先级比正在运行进程优先级低的其他进程
voidthreadmanager:
:
Drawpro(intpriority)//priority记录正在运行进程的优先级
{
readyque*rq=NULL;
intj;
for(inti=priority-1;i>=0;i--)
{
rq=adj[i].next;
if(rq!
=NULL)
{
//画优先级
cout<<"**"<
j=0;
while(rq!
=NULL)//当对应的就绪队列不为空时
{
cout<<"--->**"<pc.pid<<"**"<pc.status<<"**"<pc.life<<"**";
rq=rq->next;
j++;
if(j%3==0)
cout<}
cout<}
}
}
//新建一个进程的函数
boolthreadmanager:
:
newpro()
{
structreadyque*t=NULL;
//srand((unsigned)time(NULL));//srand()函数产生一个以当前时间开始的随机种子
for(inti=1;i<101;i++)
{
if(pidarray[i]==true)//找一个空的进程号
{
t=newreadyque;
t->pc.pid=i;
pidarray[i]=false;//宣布该进程号已被使用。
t->pc.status="ready";
t->pc.priority=rand()%50;//随机产生优先级(随机域为0~49)。
t->pc.next=NULL;
t->pc.life=rand()%5+1;//随机产生生命周期(随机域为1~5)。
t->next=adj[t->pc.priority].next;
adj[t->pc.priority].next=t;//将新建的进程的PCB插入就绪队列
returntrue;//创建进程成功
}
}
returnfalse;//找不到空的进程号,创建进程失败
}
七、实验结果及分析
(一)、新建进程
连续15次按下Ctrl+F键后新建15个进程:
(二)、开始调度
每按一次Ctrl+R将进行一次进程调度:
(三)、在一次进程调度完成后按下Ctrl+F将新建一个进程:
从上图的绿色部分可以看出按下Ctrl+F键后新建一个优先级为39,pid为15的进程。
(四)、按下Ctrl+Q键后将停止调度,输出提示信息:
八、实验总结
通过这次实验我加深理解了操作系统进程调度的过程和多级反馈队列进程调度算法。
长时间不用C++写代码未免有些生疏,这次实验同时让我复习了随机数的用法和链表的使用。
实验耗费时间的往往是那些看似微不足道的细节上,比如链表的用法:
因为输出进程信息到屏幕上时修改了指针,导致就绪队列中进程PCB丢失,调试了很久才发现这问题。
这次实验不足的地方就是本人对MFC编程不熟悉,只能在控制台下实现,用户界面不是很好。