目录
一、实验目的与要求
- 加深对作业/进程调度算法的理解;
- 进行程序设计的训练;
- 学会使用高级语言编写一个或多个算法的模拟程序。
二、实验环境
Ubuntu、centos、Windows系统
三、实验内容
使用c语言完成非抢占式SJF算法的模拟,短作业优先(非抢占式)算法按照作业或进程到达时间的先后及所需运行时间长短排队,先到的进程先调度,同时到达的进程所需运行时间短的优先调度。
每个进程由一个进程控制块PCB表示,包含以下信息:进程名、进程ID、提交(到达)系统时间、开始时间、运行时间、完成时间、进程状态(就绪、阻塞、执行)等。
1.模拟数据生成
允许用户指定进程的个数(5-25个),默认5个。
允许用户选择输入每个进程的到达时间和所需运行时间。
2.模拟程序的功能
以表格形式打印显示出每个进程(正在运行进程和等待进程)的进程名、到达时刻、开始运行时刻、结束运行时刻、现在系统时刻、进程状态、所需运行时间。
指出进程到达顺序与调度顺序,并计算每个进程的周转时间和带权周转时间。
3 .数据及算法分析
分析SJF算法的优缺点。
利用写好的非抢占SJF算法,思考抢占式SJF和优先级调度算法应该怎样写?
4.完成实验报告
对相关代码和过程进行保存,并对相关实验结果截图展示在实验报告中,其中代码部分需粘贴在实验报告中不要截图请直接贴代码。
四、实验结果展示
1.实验参考结果(1)
2.实验参考代码(2)
#include<stdio.h>
//SJF调度算法
struct process {
//进程名称
char name[10];
//进程id
int id;
//进程到达时间
int ArriveTime;
//进程开始时间
int StartTime;
//进程运行时间
int RunTime;
//进程完成时间
int FinishiTime;
//进程周转时间
float TurnTime;
//带权周转时间
float WaitTime;
//进程状态
int State;
}PCB[25];
int main() {
//模拟数据生成
int num, i, j;
int m;
int n;
printf("请输入进程数:");
scanf("%d", &num);
if (num < 5 || num>25)
{
printf("您的输入无效,默认将进程数设置为5\n");
num = 5;
}
for (i = 0; i < num; i++)
{
printf("请输入第%d个进程的id、name、到达时间、所需运行时间。(数据间用空格间隔)\n", i + 1);
scanf("%d %s %d %d", &PCB[i].id, PCB[i].name, &PCB[i].ArriveTime, &PCB[i].RunTime);
}
//比较出初始到达时间
struct process t1;
for (i = 0; i < num - 1; i++)
{
for (j = i + 1; j < num; j++)
{
if (PCB[i].ArriveTime > PCB[j].ArriveTime)
{
t1 = PCB[i];
PCB[i] = PCB[j];
PCB[j] = t1;
}
}
}
//挑选出运行时间候选圈内到达的进程,并比较运行时间
struct process t2;
for (i = 0; i < num - 1; i++)
{
for (j = i + 1; j < num; j++)
{
//比较运行时间与到达时间,候选圈
if (PCB[i].RunTime < PCB[j].ArriveTime)
{
//比较运行时间
for (m = i + 1; m < j; m++)
{
for (n = m + 1; n < j + 1; n++)
{
if (PCB[m].RunTime > PCB[n].RunTime)
{
t2 = PCB[m];
PCB[m] = PCB[n];
PCB[n] = t2;
}
}
}
}
}
}
//比较初始运行时间
struct process t3;
for (i = 0; i < num - 1; i++)
{
for (j = i + 1; j < num; j++)
{
if (PCB[i].ArriveTime == PCB[j].ArriveTime)
{
if (PCB[i].RunTime > PCB[j].ArriveTime)
{
t3 = PCB[i];
PCB[i] = PCB[j];
PCB[j] = t3;
}
}
}
}
//进程开始运转
printf("\n");
for (i = 0; i < num; i++)
{
printf("进程%s开始运转......\n", PCB[i].name);
}
//计算完成、运转时间
int NowTime = 0;
for (i = 0; i < num; i++)
{
//开始时间=到达时间
PCB[i].StartTime = NowTime;
//完成时间=开始时间+运转时间
PCB[i].FinishiTime = PCB[i].StartTime + PCB[i].RunTime;
//周转时间=结束时间-到达时间
PCB[i].TurnTime = PCB[i].FinishiTime - PCB[i].ArriveTime;
//带权运转时间=周转时间/运行时间
PCB[i].WaitTime = PCB[i].TurnTime / PCB[i].RunTime;
//当前时间=完成时间
NowTime = PCB[i].FinishiTime;
}
//显示进程表格
printf("\n");
printf(" id 进程名 到达时间 开始时间 结束时间 周转时间 带权周转时间\n");
for (i = 0; i < num; i++)
{
printf("%5d %5s %5d %8d %8d %.6f %.6f\n", PCB[i].id, PCB[i].name, PCB[i].ArriveTime, PCB[i].StartTime, PCB[i].FinishiTime, PCB[i].TurnTime, PCB[i].WaitTime);
}
return 0;
}
3.实验参考结果(2)
4.实验代码(2)
//非抢占式短作业优先调度算法模拟
#include "stdio.h"
typedef struct
{
//struct PCB* link; //PCB链表指针
char name; //进程名
int id; //进程id
int atime; //进程到达时间
int stime; //进程开始时间
int runtime; //进程运行时间
int ftime; //进程完成时间
float total; //周转时间
float welght; //带权周转时间(周转系数)
int status; //进程状态
}PCB;
enum bool{false = 0,true = 1 };
void init(PCB p[],int n){//初始化进程
//printf("请输入进程个数\n");
//scanf("%d",&n);
int i;
for(i=0;i<n;i++){
printf("请输入第%d个进程的id、name、到达时间、所需运行时间。数据间用空格间隔\n",i+1);
scanf("%d %c %d %d",&p[i].id,&p[i].name,&p[i].atime,&p[i].runtime);
p[i].status=0;//0代表已输入,可能还未到达系统
}
}
void swap(PCB *p,PCB *q){//交换p和q的值
PCB temp;
temp=*p;
*p=*q;
*q=temp;
}
void sort(PCB p[],int n){//对进程按照到达时间先后及运行时间长短排序
int i,j;
enum bool change;
//PCB temp;
for(i=0;i<n;i++){
change = false;
for(j=0;j<n-i-1;j++){
if(p[j].atime>p[j+1].atime){
swap(&p[j],&p[j+1]);
}
//若到达时间一致,应再比较运行时间
if(p[j].atime==p[j+1].atime){
if(p[j].runtime>p[j+1].runtime)
swap(&p[j],&p[j+1]);
}
}
if(!change)
return ;
}
}
int select(PCB p[],int n,int k){//选出已到达系统但运行时间最短的进程
int time;
int i,j=k;
//多个进程已到达系统选运行时间最短的
time=p[k].runtime;
for(i=1;i<n;i++){
if(p[i].status==1 && p[i].runtime<time){
time=p[i].runtime;
j=i;
}
}
return j;
}
void process(PCB p[],int n){//开始进程调度
int i,j,k=0,time,count=0;
time=p[0].atime+p[0].runtime;//time表示当前时间
printf("进程%c开始运行……\n",p[k].name);
p[k].status=2;//运行完成状态
p[k].ftime=time;
p[k].stime=p[k].atime;
p[k].total=p[k].ftime-p[k].atime;
p[k].welght=p[k].total/p[k].runtime;
for(i=1;i<n;i++){//循环处理n-1个进程
//判断下一个进程是否达到系统。
if(p[i].atime>time)//当前进程的到达时间比系统时间大,则进程还未到达系统,系统时间直接置为下一个进程达到时间
time=p[i].atime;
for(j=0;j<n;j++){//找到所有已到达系统的进程
//if(count==n-1) break;//如果剩余n-1个进程已全部到达系统,则不需要再检测
if(p[j].status!=2 && p[j].atime<=time){
//count++;
p[j].status=1;//代表已到达系统,等待调度,就绪;
}
}
for(j=0;j<n;j++){//找到第一个等待运行进程在数组中的下标
if(p[j].status==1 ){
count=j;
break;
}
}
k=select(p,n,count);//选出已到达系统但运行时间最短的进程
time=time+p[k].runtime;//time表示当前时间
printf("进程%c开始运行……\n",p[k].name);
p[k].status=2;//运行完成状态
p[k].ftime=time;
p[k].stime=p[k].ftime-p[k].runtime;
p[k].total=p[k].ftime-p[k].atime;
p[k].welght=p[k].total/p[k].runtime;
}
}
void print(PCB p[],int n){
int i;
printf("id 进程名 到达时间 运行时间 开始时间 结束时间 周转时间 带权周转时间\n");
for(i=0;i<n;i++){
printf("%4d %4c %8d %8d %8d %12d %12f %12f\n",p[i].id,p[i].name,p[i].atime,p[i].runtime,p[i].stime,p[i].ftime,p[i].total,p[i].welght);
}
}
int main(){
PCB p[6];
int n=0;
printf("请输入进程个数\n");
scanf("%d",&n);
init(p,n);
sort(p,n);
process(p,n);
print(p,n);
return 1;
}
五、实验总结和思考
编写代码时,我发现自己对C语言的基础知识已经不太熟悉了,并且,自己对SJF的算法没有进行过深入的探究和学习。因此,我要多找时间去巩固C语言基础知识,多研究SJF算法等方面的内容,认真学习优秀的教程和代码,尽量在电脑上进行相关实践,使自己能够熟练地掌握这方面编程知识。
而且,当代码运行出现问题时,在经过自己的认真思考和资料查找之后,应主动与同学还有老师进行交流,多制作出几套方案,以锻炼自己解决问题和与他人协作的能力。
总之,学无止境,我还有许许多多方面的能力都还需要提高,今后我会更加严格要求自己,加强自己的学习能力。