一、实验题目: 模拟进程调度功能
二、实验目的: 通过本实验,进一步掌握进程调度的功能和实现原理。
三、实验环境:
1、硬件:PC机及其兼容机。
2、软件:Windows OS,MS—DOS OS,Turbo C 或 C++、VC++等。
四、实验内容:
1、 设计进程调度功能,至少模拟两种以上调度算法。如:优先级调度算法、时间片调度算法等。
2、 进程调度功能作为一个函数 scheduler,加入到实验题目一中。
3、 进程调度程序从就绪队列中挑选进程,若队列为空,应显示“无就绪进程无法调度”的提示信息。
4、 若选上一个进程,以显示:进程名、状态、时间片、优先级等信息表示一个进程被执行。若运行完,应删除相应 PCB。
五、运行示例:
六、算法流程图:
七、程序清单:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<windows.h>
int count=0;//记录进程数目
typedef struct PCB{
char pname[10];//进程名
int ppri;//优先级,值越小优先级越高
int pruntime;//运行时间
int pstatus;//运行状态 1-就绪,2运行,3阻塞
struct PCB *next;//指针,指向下一个PCB
}PCB;
void menu(){
printf("---------OS实验一:模拟进程创建、阻塞、唤醒、终止原语---------\n");
printf("----------------------------1.创建----------------------------\n");
printf("----------------------------2.调度----------------------------\n");
printf("----------------------------3.阻塞----------------------------\n");
printf("----------------------------4.唤醒----------------------------\n");
printf("----------------------------5.删除----------------------------\n");
printf("----------------------------6.显示----------------------------\n");
printf("----------------------------0.返回上一层----------------------\n");
printf("---------------------请输入您需要的功能(0-6)------------------\n");
printf("--------------------------------------------------------------\n");
printf("各功能简要说明:\n");
printf("创建:在本实验中,该功能仅实现建立 PCB,初始化 PCB,并将该 PCB放入就绪队列中。\n");
printf("优先级调度:选择该功能选项时,系统将从就绪队列中选择优先级最高的进程,使该进程处于执行状态(将进程 PCB 的内容显示在屏幕上,显示完成后,该进程结束,即撤销该进程的 PCB)。\n");
printf("时间片调度:每选择一次该功能,将就绪队列中所有进程的内容显示在屏幕上,并将每个执行进程的执行时间减去一个时间片,若某进程的剩余时间小于等于0,则表明该进程运行结束,撤销该进程的PCB。\n");
printf("阻塞:在本实验中,实现的功能为,根据用户输入的进程名称查看该进程是否处在运行状态,若处在运行状态,修改该进程PCB的状态,并将该进程转入阻塞队列;若该进程处在其它状态,则给出相应的提示信息;若该进程不存在,也需要给出相应的提示信息。\n");
printf("唤醒:功能类似阻塞功能,注意:若阻塞队列为空,则不能执行唤醒功能。\n");
printf("终止:根据用户输入要结束的进程名称,从就绪队列、阻塞队列和正在运行的进程中找到相应的进程 PCB,并将该 PCB 从相应队列中删除。若该进程不存在,需要给出提示。\n");
printf("显示:将就绪队列、阻塞队列中的进程列表和正在运行的进程显示出来。\n");
}
void fprior(PCB *ready,PCB *run){
PCB *p,*q;
int maxpri=INT_MAX;
p=ready;
while(p->next){//在将p置于就绪队列队尾的同时寻找优先级最高的节点,用q表示那个节点的前一个节点
if(p->next->ppri<maxpri)
q=p;
p=p->next;
}
p->next=run->next;
run->next=NULL;//删除run队列中的结点
p=q->next;//p就是优先级最高节点
q->next=p->next;//将p进程从就绪队列删除;
run->next=p;//将p进程插入到run队列中。
}
void ftimeschedule(PCB *ready,PCB *run){
PCB *p,*q;
int time;
int flag=1;
p=ready;
while(p->next)//将p置于就绪队列队尾
p=p->next;
p->next=run->next;
run->next=NULL;//删除run队列中的结点
printf("请输入时间片大小:");//输入系统设定的时间片;
scanf("%d",&time);
p=ready->next;
while(p && flag){//就绪队列非空
p->pstatus=1;//从就绪队列中拿下第一个结点p;将结点p的状态修改为1;
ready->next=p->next;
run->next=p;
p->next=NULL;
p->pruntime-=time;//将结点p的运行时间减去一个时间片;
printf("进程名 剩余时间\n");
printf("%s\t\t",p->pname);
printf("%d\n",p->pruntime);//显示结点p的名称及剩余时间;
if(p->pruntime>0){//若剩余时间>0,将结点p从run队列中拿下,修改状态后放入就绪队列的尾部
q=ready;
while(q->next)//将q置于就绪队列队尾
q=q->next;
q->next=run->next;
run->next=NULL;
}
else{//否则 从run队列中删除该结点;
free(p);
run->next=NULL;
printf("运行结束,%s进程退出内存!\n",p->pname);
}
printf("继续运行一个时间片?1-继续 0-退出\n");
scanf("%d",&flag);
getchar();
p=ready->next;
}
printf("退出本次时间片轮转运行!");
}
void frun(PCB *ready,PCB *run,int method){//从就绪队列中选队首进程运行,保证有一个进程处于运行状态
int flag=1;
while(flag==1){
switch(method){
case 1:fprior(ready,run);break;//fprior实现高优先权优先调用
case 2:ftimeschedule(ready,run);break;//ftimeschedule实现时间片轮转调度算法
}
printf("Do you want to run another one 1:yes 0:no:");
scanf("%d",&flag);
}
}
void insert(PCB *ready,PCB *temp){//将新创建的进程插入就绪队列
PCB *p;
p=ready;
while(p->next)//找尾结点
p=p->next;
p->next=temp;
temp->next=NULL;
}
int check(PCB *head,PCB *temp){//检查temp进程与已有进程是否重复,重复输出0
PCB *p=head;
while(p->next){
p=p->next;
if(strcmp(p->pname,temp->pname)==0)
return 0;
}
return 1;
}
void Delete(PCB *head,PCB *temp){/*head为链表头结点,temp为将要删除的结点*/
PCB *q=head,*p=head->next;
while(p)//寻找temp的上一个节点
if(p->pname==temp->pname){
q->next=p->next;
free(temp);
return;
}
else{
p=p->next;
q=q->next;
}
}
void fcreate(PCB *ready,PCB *run,PCB *block,int method){//创建进程
int compare1,compare2,compare3;
int count=0;//记录进程数量
int flag=1;
PCB *temp;//一个新节点
system("cls");
while(flag){
temp=(PCB*)malloc(sizeof(PCB));
printf("---------------进程创建---------------\n");
printf("请输入进程名:");
scanf("%s",temp->pname);
getchar();
compare1=check(ready,temp);//检查进程是否与就绪进程重复
compare2=check(run,temp);//检查进程是否与运行进程重复
compare3=check(block,temp);//检查进程是否与阻塞进程重复
if( !(compare1 && compare2 && compare3) ){
printf("已有进程中已有该名称进程,创建失败!\n");
system("pause");
return;
}
else if( count>=10 ){
printf("系统当前进程已满十个,创建失败!\n");
system("pause");
return;
}
printf("请输入进程优先级(值越小优先级越高):");
scanf("%d",&temp->ppri);
getchar();
printf("请输入进程运行时间:");
scanf("%d",&temp->pruntime);
getchar();
temp->pstatus=1;//将新创建进程放入就绪队列
insert(ready,temp);
printf("插入成功!\n");
count++;
printf("Do you want to create anthoer one(1:yes 0:no):");
scanf("%d",&flag);
}
if(run->next==NULL)
frun(ready,run,method);
}
void fblock(PCB *ready,PCB *run,PCB *block,int method){//阻塞进程函数
char name[10];
PCB *p,*q;
system("cls");
printf("---------------阻塞进程---------------\n");
printf("请输入你要阻塞的进程名称:");
scanf("%s",name);
getchar();
p=block->next;
while(p){//在阻塞进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程已在阻塞队列中,不可重复放入\n");
system("pause");
return;
}
p=p->next;
}
p=ready->next;
while(p){//在就绪进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程在就绪队列中,无法放入\n");
system("pause");
return;
}
p=p->next;
}
p=run->next;
while(p){//在运行进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程处于运行状态,准备将该进程放入阻塞队列\n");
system("pause");
p->pstatus=3;
q=block;
while(q->next)//使q在阻塞队列队尾节点
q=q->next;
q->next=p;
run->next=NULL;
printf("已经将该进程放入阻塞队列,完成!\n");
system("pause");
frun(ready,run,method);//将执行进程阻塞,需要将cpu重新分配
return;
}
p=p->next;
}
if(!p){
printf("\n系统中无该进程\n");
system("pause");
return;
}
}
void fwakeup(PCB *ready,PCB *run,PCB *block,int method){//唤醒进程
char name[10];
PCB *p,*q;
system("cls");
printf("\n---------------唤醒进程----------------\n");
printf("\n---------输入你要唤醒的进程名称:-------");
scanf("%s",name);
getchar();
q=block;//q为前一个节点
p=q->next;
while(p){//在阻塞进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程处于阻塞状态,准备将该进程放入就绪队列\n");
system("pause");
q->next=p->next;
p->pstatus=1;
q=ready;
while(q->next)//使q为就绪队列队尾节点
q=q->next;
q->next=p;
printf("已经将该进程放入就绪队列,完成!\n");
if(run->next == NULL)
frun(run,ready,method);
return;
}
p=p->next;
q=q->next;
}
p=run->next;
while(p){//在运行进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程在运行队列中\n");
system("pause");
return;
}
p=p->next;
}
p=ready->next;
while(p){//在就绪进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
printf("\n该进程在就绪队列中\n");
system("pause");
return;
}
p=p->next;
}
if(!p){
printf("系统中无该进程名称\n");
system("pause");
return;
}
}
void fstop(PCB *ready,PCB *run,PCB *block,int method){//终止进程函数
char name[10];
PCB *p;
system("cls");
printf("\n---------------终止进程----------------\n");
printf("\n--------输入你要终止的进程名称:--------");
scanf("%s",name);
getchar();
p=block->next;
while(p){//在阻塞进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
Delete(block,p);//调用删除结点函数
count--;
printf("\n进程终止成功\n");
system("pause");
return;
}
p=p->next;
}
p=run->next;
while(p){//在运行进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
Delete(run,p);//调用删除结点函数
count--;
printf("\n进程终止成功\n");
frun(ready,run,method);
system("pause");
return;
}
p=p->next;
}
p=ready->next;
while(p){//在就绪进程中寻找pname为name的进程
if(strcmp(p->pname,name)==0){
Delete(ready,p);//调用删除结点函数
count--;
printf("\n进程终止成功\n");
system("pause");
return;
}
p=p->next;
}
if(!p){
printf("进程队列中无该进程\n");
system("pause");
}
}
void fshow(PCB *ready,PCB *run,PCB *block){//显示队列进程
int readycount=1,runcount=1,blockcount=1;
PCB *p;
system("cls");
p=block;/*列出阻塞队列列表*/
if(p->next==NULL){
printf("阻塞队列中没有进程,请返回主界面创建进程\n");
system("pause");
}
else{
p=p->next;//指针指到第一个结点
printf("\n--阻塞队列--\n");
while(p){
printf("%d)进程名:%s\n",block++,p->pname);
printf(" 进程优先级:%d\n",p->ppri);
printf(" 进程运行时间:%d\n",p->pruntime);
p=p->next;
}
}
printf("\n");
p=run;/*列出运行队列列表*/
if(p->next==NULL){
printf("运行队列中没有进程,请返回主界面创建进程\n");
system("pause");
}
else{
p=p->next;//指针指到第一个结点
printf("\n--运行队列--\n");
while(p){
printf("%d)进程名:%s\n",run++,p->pname);
printf(" 进程优先级:%d\n",p->ppri);
printf(" 进程运行时间:%d\n",p->pruntime);
p=p->next;
}
}
printf("\n");
p=ready;/*列出就绪队列列表*/
if(p->next==NULL){
printf("就绪队列中没有进程,请返回主界面创建进程\n");
system("pause");
}
else{
p=p->next;//指针指到第一个结点
printf("\n--就绪队列--\n");
while(p){
printf("%d)进程名:%s\n",ready++,p->pname);
printf(" 进程优先级:%d\n",p->ppri);
printf(" 进程运行时间:%d\n",p->pruntime);
p=p->next;
}
}
printf("\n");
printf("进程显示完毕");
system("pause");
}
void fmenu(int select){//主函数
PCB *ready,*run,*block;//head1为阻塞队列,head2为运行队列(单核),head3为就绪队列
ready=(PCB*)malloc(sizeof(PCB));//申请空间
run=(PCB*)malloc(sizeof(PCB));
block=(PCB*)malloc(sizeof(PCB));
ready->next=NULL;//无节点,置空
run->next=NULL;
block->next=NULL;
if(!ready || !run || !block)//只要有一个队列申请空间失败,则进入if
{ printf("申请空间失败,退出!");
system("pause");
exit(0);
}
while(1){
int choice;
system("cls");
menu();
scanf("%d",&choice);
switch(choice){
case 0:exit(0);break;
case 1:fcreate(ready,run,block,select);break;//创建新进程放入就绪队列
case 2:fblock(ready,run,block,select);break;//阻塞运行进程
case 3:fwakeup(ready,run,block,select);break;//唤醒阻塞进程
case 4:fstop(ready,run,block,select);break;//终止的进程可能位于某一个队列
case 5:fshow(ready,run,block);break;//显示三个队列的进程
default:printf("输入错误");break;
}
}
}
void main(){
int flag=1;
int select;
while(flag){
printf("-----------先选择系统调度算法-----------\n");
printf("-----------1.高优先权优先调度-----------\n");
printf("-----------2.时间片轮转法调度-----------\n");
printf("-----------------0.退出-----------------\n");
printf("请输入选择:");
scanf("%d",&select);
switch(select){
case 1:
case 2:fmenu(select);break;
case 0:flag=0;break;
default: printf("input error!\n");break;
}
}
}
八、程序中使用的数据结构及符号说明:
进程名用 P1,P2 标识
优先级//优先级,值越小优先级越高
运行时间
状态(1-就绪,2运行,3阻塞)
指针:指向下一个 PCB。
typedef struct PCB{
char pname[10];//进程名
int ppri;//优先级,值越小优先级越高
int pruntime;//运行时间
int pstatus;//运行状态 1-就绪,2运行,3阻塞
struct PCB *next;//指针,指向下一个PCB
}PCB;
int count=0;//记录进程数目
PCB *ready,*run,*block;//block为阻塞队列,run为运行队列(单核),ready为就绪队列
九、调试程序时出现问题说明及解决的方法:
- 首先,出于写实验一的经验,我把head123换成了直白的ready、run、block三个队列,直白明了,易于理解。
- 在将p置于队尾时,使用
p=ready->next;while(p) p=p->next;
结果出错
解决方法:修改为p=ready;while(p->next) p=p->next;
好几处这样,思考不严谨。 - 使用
INT_MAX
需要#include<windows.h>
声明。 c p->pstatus=1;//从就绪队列中拿下第一个结点p;将结点p的状态修改为1; ready->next=p->next; run->next=p;
此时运行结果出错
解决方法:是因为p->next
还有节点,加上p->next=NULL;
语句。- 经过思考,PPT中
/*若run队列为空,则调用run函数选择新的进程运行*/
if(run->next==NULL)
frun(ready,run,block,method);
printf("Do you want to create anthoer one(1:yes 0:no):");
scanf("%d",&flag);
这样的执行顺序是有问题的
解决方法:printf("Do you want to create anthoer one(1:yes 0:no):");
scanf("%d",&flag);
}
if(run->next==NULL)
frun(ready,run,method);
即等创建循环结束后再去运行frun函数。