一、实验目的
用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
二、实验内容
编写进程调度算法:采用基于时间片轮转的最高优先数优先算法(即把处理机分配给优先数最高的进程)。
- 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、需要运行时间、已用CPU时间、进程状态等等。
- 进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。
- 每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。
- 进程的运行时间以时间片为单位进行计算。
- 就绪进程获得 CPU后都只能运行一个时间片,用已占用CPU时间加1来表示。
- 如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。
- 每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。
- 重复以上过程,直到所有进程都完成为止。
三、编程环境及工具
Dev-C++ 5.11
四、具体设计及有关说明
设计思想:
- 通过循环将输入的进程信息存入进程结构体数组中,并初始化结构体数组的值;
- 通过循环计算需要循环的总次数;
- 开始总次数的循环:①对数组进行排序:根据数组的状态(“F”或“W”)将数组分为数组p1和p2,然后p1根据输入先后顺序排序,p2根据优先级数从高到低排序(若优先级数相同,则根据等待时间从大到小排序),再将p1、p2按顺序赋值给进程结构体数组p;②在p数组从p2赋值过来的数组(即状态为“W”)的第一个数组的队列信息进行数据更新(即将需要运行的第一个进程进行运行);
- 循环结束,进程运行结束;
数据结构:
运用了结构体数组,结构体代表进程的信息汇总,结构体数组来表示多个进程;
流程图:
- 主流程图:
- 总次数的循环的流程图:
代码:
#include<bits/stdc++.h>
#include<conio.h>
using namespace std;
int N; //定义总进程数
struct node //定义进程结构体
{
char name[10]; //进程名
int ndtime; //进程要求运行的时间
char state; //进程状态3种,R表示运行状态,W表示就绪状态,F表示完成状态
int super; //优先数
int wait; //等待时间
int runtime; //已经运行时间
int jointime; //进程输入的时间
};
typedef struct node P; //用P替代结构体的类型名
//排序算法 :根据数组的状态(“F”或“W”)将数组分为数组p1和p2
//然后p1根据输入先后顺序排序,p2根据优先级数从高到低排序(若优先级数相同,则根据等待时间从大到小排序)
//再将p1、p2按顺序赋值给进程结构体数组p
void Sort(P* p)
{
//分别定义结构体数组p1、p2
P* t= new P[1];
P* p1 = new P[N+2];
P* p2 = new P[N+2];
int p11=0,p22=0;
//通过循环,将根据数组的状态(“F”或“W”)将数组p分为数组p1和p2
for(int i=0;i<N;i++)
{
if(p[i].state=='F')
{
p1[p11]=p[i];
p11++;
}
else
{
p2[p22]=p[i];
p22++;
}
}
//将p1根据输入先后顺序排序
for (int i = 0; i < p11-1; i++)
{
for (int j = 0; j < p11-1 - i; j++)
{
if (p1[j].jointime > p1[j + 1].jointime)
{
t[0] = p1[j + 1];
p1[j + 1] = p1[j];
p1[j] = t[0];
}
}
}
//p2根据优先级数从高到低排序(若优先级数相同,则根据等待时间从大到小排序)
for (int i = 0; i < p22-1; i++)
{
for (int j = 0; j < p22-1 - i; j++)
{
if (p2[j].super < p2[j + 1].super )
{
t[0]= p2[j + 1];
p2[j + 1] = p2[j];
p2[j] = t[0];
}
else if(p2[j].super == p2[j + 1].super)
{
if(p2[j].wait < p2[j + 1].wait )
{
t[0] = p2[j + 1];
p2[j + 1] = p2[j];
p2[j] = t[0];
}
}
}
}
//将p1、p2按顺序赋值给进程结构体数组p
int k=0;
for(int i=0;i<=p11-1;i++)
{
p[k]=p1[i];
k++;
}
for(int i=0;i<=p22-1;i++)
{
p[k]=p2[i];
k++;
}
//释放空间
delete [] p1;
delete [] p2;
delete t;
}
int main ()
{
int sumnum = 0,i,j; //sumnum表示执行所有进程总需的时间片长度
printf("\n(^_^)请输入进程总个数:");
scanf("%d",&N);
printf("\n");
P* p = new P[N]; //定义结构体数组
//通过循环输入进程信息,同时进行变量初始化
for(i = 0;i < N;i++)
{
printf("\n进程号No.%d:\n",i);
printf("\n输入进程名:");
scanf("%s",p[i].name);
printf("\n输入进程优先数<0~99>:");
scanf("%d",&(p[i].super));
printf("\n输入进程运行时间:");
scanf("%d",&(p[i].ndtime));
p[i].wait = 0;
p[i].runtime = 0;
p[i].jointime = i;
if(p[i].ndtime == 0)
p[i].state = 'F';
else
p[i].state = 'W';
}
//通过循环计算循环总次数
for(i = 0;i < N;i++) sumnum += p[i].ndtime;
//进行循环,对数组进行排序,在p数组从p2赋值过来的数组(即状态为“W”)的第一个数组的队列信息进行数据更新(即将需要运行的第一个进程进行运行)
int adjust=0;
for(i = 0;i < sumnum;i++)
{
printf("\n按任意键继续......");
getch();
int k;
printf("\n*-*-*-*-*-*-* The execute number: %d *-*-*-*-*-*-*\n",i + 1);
Sort(p); //排序
//通过循环,找到数组中需要运行的第一个进程
for(j = 0;p[j].state == 'F' && j < N;j++);
//根据 j的范围来判断是否进程是否全部运行完,其实进程全部运行完后会跳出循环,程序不会再跑到这里
if(j < N)
{
p[j].state = 'R';
p[j].super--;
//防止优先级为负值
if(p[j].super<0)
{
p[j].super=0;
adjust=1; //作为优先级数为 0的判断数,在进行后续输出时作为判断依据
}
p[j].runtime++;
p[j].wait = 0;
//通过循环,将当前运行的进程的后面就绪进程的等待时间加一
for(k = j + 1;k < N;k++)
p[k].wait++;
}
//打印当前运行进程的信息
printf("\n*-*-*-*-*-* 当前正在运行的进程是: %s *-*-*-*-*-*",p[j].name);
printf("\np_name\tstate\tsuper\tndtime\truntime\t");
printf("\n |%s\t|%c\t|%d\t|%d\t|%d\n",p[j].name,
p[j].state,adjust==1?p[j].super:p[j].super+1,p[j].ndtime,p[j].runtime-1);
//打印此时就绪进程的信息
printf("\n*-*-*-*-*-* 当前就绪队列状态为: *-*-*-*-*-*\n");
for(k = j + 1;k < N && i < sumnum - 1;k++)
if(p[k].state != 'F')
{
printf("\np_name\tstate\tsuper\tndtime\truntime\t");
printf("\n |%s\t|%c\t|%d\t|%d\t|%d\n",p[k].name,
p[k].state,p[k].super,p[k].ndtime,p[k].runtime);
}
//判断当前运行进程是否完成
if(p[j].ndtime == p[j].runtime)
{
p[j].state = 'F';
printf("\n时间片到期,此时进程 [ %s ] 已完成.\n",p[j].name);
}
//需要再进行排序,因为完成队列可能更新
Sort(p);
printf("\n*-*-*-*-*-* 当前完成队列状态为: *-*-*-*-*-*\n");
for(k = 0;k < j+1 && i < sumnum ;k++)
if(p[k].state == 'F')
{
printf("\np_name\tstate\tsuper\tndtime\truntime\t");
printf("\n |%s\t|%c\t|%d\t|%d\t|%d\n",p[k].name,
p[k].state,p[k].super,p[k].ndtime,p[k].runtime);
}
adjust=0; //依次循环后,优先级数是否为零的判断数重置为一
}
printf("\n进程已经全部完成.\n");
delete[] p; //释放空间
return 0;
}