操作系统进程调度实验报告

一、实验目的

        用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解

二、实验类别

        综合性实验。综合高级语言编程、进程调度模型、进程调度算法及数据结构等多方面的知识

三、实验示例

例题: 设计一个有 N个进程共行的进程调度程序

进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。

每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。

进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输

入的时间。

  进程的运行时间以时间片为单位进行计算。

  每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。

  就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。

  如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。

  每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。   

重复以上过程,直到所要进程都完成为止。

调度算法的流程图如下 :

四、源代码

#include "stdio.h" 
#include <stdlib.h> 
#include <conio.h> 
#define getpch(type) (type*)malloc(sizeof(type)) //分配type类型大小的空间
#define NULL 0 
struct pcb { /* 定义进程控制块PCB */ 
char name[10]; //进程名
char state; //进程状态
int super; //进程优先级
int ntime; //进程总共需要运行的时间
int rtime; //进程已经运行的时间
struct pcb* link; //指向后继节点的指针
}*ready=NULL,*p;  //ready指针永远指向队列的第一个进程
typedef struct pcb PCB; 
  
sort() /* 建立对进程进行优先级排列函数*/ 
{ 
PCB *first, *second; // 指针second指向队列中当前处理的进程,指针first指向second的前驱节点,指针p指向准备插入队列的进程;
int insert=0; //判断是否
if((ready==NULL)||((p->super)>(ready->super))) /*优先级最大者,插入队首*/ 
{ 
p->link=ready; //p指向的进程优先级最高,要成为队列中新的队首节点,即ready要修改指向p;
ready=p; 
} 
else /* 如果队列有至少一个进程,则进程比较优先级,插入适当的位置中*/ 
{ 
first=ready; // first指向队首节点;
second=first->link; // second指向第2个节点;
while(second!=NULL) //如果有第2个节点,即队列至少有2个节点;
{ 
if((p->super)>(second->super)) /*若插入进程比当前进程优先数大,*/ 
{ /*插入到当前进程前面*/ //p指向的进程要插入到first和sencond之间,修改指针;
p->link=second; 
first->link=p; 
second=NULL; //找到了进程插入的位置,把second设为NULL,退出while循环;
insert=1; //insert为1表示p指向的进程插入在两个进程之间;
} 
else /* 插入进程优先数最低,则插入到队尾*/ 
{ 
first=first->link; // 此时first指向原队列最后一个进程;
second=second->link; //此时second为NULL;
} 
} 
if(insert==0) first->link=p; // insert为0表示p指向的进程插入到队尾
} 
}

input() /* 建立进程控制块函数*/ 
{ 
int i,num; 
//clrscr(); /*清屏*/ 
printf("\n 请输入进程号?"); //输入需要调度的进程数量
scanf("%d",&num); 
for(i=0;i<num;i++) //依次输入每个进程控制块的信息;
{ 
printf("\n 进程号No.%d:\n",i); 
p=getpch(PCB); 
printf("\n 输入进程名:"); 
scanf("%s",p->name); 
printf("\n 输入进程优先数:"); 
scanf("%d",&p->super); 
printf("\n 输入进程运行时间:"); 
scanf("%d",&p->ntime); 
printf("\n"); 
p->rtime=0;p->state='w'; 
p->link=NULL; 
sort(); /* 调用sort函数*/ //把新创建的进程按优先级插入到队列中;
} 
} 
int space() //获取当前队列的长度,即需要调度的进程个数;
{ 
int l=0; PCB* pr=ready; //pr指向队列第一个进程,即对首进程
while(pr!=NULL) //依次遍历整个队列,计算长度
{ 
l++; //是字符l,不是数字1,代表队列长度;
pr=pr->link;
} 
return(l); 
} 
disp(PCB * pr) /*建立进程显示函数,用于显示当前进程的信息*/ 
{ 
printf("\n qname \t state \t super \t ndtime \t runtime \n"); 
printf("|%s\t",pr->name); 
printf("|%c\t",pr->state); 
printf("|%d\t",pr->super); 
printf("|%d\t",pr->ntime); 
printf("|%d\t",pr->rtime); 
printf("\n"); 
}
check() /* 建立进程查看函数 */ //查看当前队列中每个进程信息
{ 
PCB* pr; 
printf("\n **** 当前正在运行的进程是:%s",p->name); /*显示当前运行进程*/ 
disp(p); 
pr=ready; // pr指向队列对首进程
printf("\n ****当前就绪队列状态为:\n"); /*显示就绪队列状态*/ 
while(pr!=NULL) //循环遍历队列中每个进程
{ 
disp(pr); 
pr=pr->link; 
} 
} 
destroy() /*建立进程撤消函数(进程运行结束,撤消进程)*/ 
{ 
printf("\n 进程 [%s] 已完成.\n",p->name); 
free(p); 
} 
running() /* 建立进程就绪函数(进程运行时间到,置就绪状态*/ 
{ 
(p->rtime)++; //p指向当前运行进程,即从原队列中的对首进程,运行次数加1,rtime表示已运行的时间片;
if(p->rtime==p->ntime) //如果进程需要运行总时间ntime和已运行时间rtime相等,表示该进程已经运行完毕,需要撤销;
destroy(); /* 调用destroy函数*/ 
else //如果该进程没有运行完毕,则使它的优先级减1,状态变为就绪,重新按优先级顺序插入到队列中;
{ 
(p->super)--; 
p->state='w'; 
sort(); /*调用sort函数*/ 
} 
} 
main() /*主函数*/ 
{ 
int len,h=0; //len:队列进程的个数;h:进程调度的时间片次数
char ch; // 获取getchar()函数的字符
input(); //输入要处理进程控制块信息
len=space(); //当前进程队列的长度,即要处理的进程数量
while((len!=0)&&(ready!=NULL)) //若队列不为空,即还有进程需要处理;
{ 
ch=getchar(); //从键盘获取字符
h++; // h:进程执行的时间片次数序号
printf("\n The execute number:%d \n",h); //
p=ready;  // ready永远指向队列的对首进程,p此时也指向队列的对首进程,但该对首进程需要出队列以便运行,;
ready=p->link; //原队列的第2个进程成为新的对首进程
p->link=NULL; //原对首进程出队列后,没有后继;
p->state='R'; //原对首进程出队列后状态变为执行;
check(); //查看当前队列中所有进程的信息,即原对首进程出队列后
running();//原对首进程运行
printf("\n 按任一键继续......"); 
ch=getchar();//从键盘获取字符
} 
printf("\n\n 进程已经完成.\n"); 
ch=getchar();//从键盘获取字符
}

五、运行截图

 六、报告总结

        通过本次实验,进程动态调度的过程与人工分析的结果一致,基本达到预期的目标。通过用户自己定义进程号、进程名、进程优先数、进程运行时间。优先数高的进程先进入运行状态,其他进程则为就绪状态。若优先数高的进程运行一个时间片后仍需运行,则进入就绪状态,该进程优先数-1。若进程运行一个时间片后,已经达成所需要的运行时间,则该进程完成,进入完成状态。如果就绪队列里存有多个优先数相同的进程,则根据进程号先来先得的原则运行。

猜你喜欢

转载自blog.csdn.net/henry594xiaoli/article/details/129975734