39 进程调度实验
一、 实验目的
1.用高级语言完成一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
2.实验要求
3.设计一个有 N(N不小于5)个进程并发执行的进程调度模拟程序。
4.进程调度算法:“时间片轮转法”调度算法对N个进程进行调度。
二、 实验内容和要求
完成两个算法(简单时间片轮转法、多级反馈队列调度算法)的设计、编码和调试工作,完成实验报告。
1) 每个进程有一个进程控制块(PCB)表示。进程控制块包含如下信息:进程名、优先级、到达时间、需要运行时间、已用CPU时间、进程状态等等。
2) 每个进程的状态可以是就绪 r(ready)、运行R(Running)、或完成F(Finished)三种状态之一。
3) 就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。
4) 如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,应把它插入就绪队列等待下一次调度。
5) 每进行一次调度,程序都打印一次运行进程、就绪队列中各个进程的 PCB,以便进行检查。
6) 重复以上过程,直到所要进程都完成为止。
三、 实验方法、步骤及结果测试
1.源程序名:1125.c
可执行程序名:1125.exe
2.原理分析及流程图
1)理解简单轮转法与多级反馈队列调度算法;
2)流程图:
3.主要程序段及其解释:
1 #include<stdio.h> 2 3 #define MAX 24 4 5 typedef struct node 6 { 7 char name[10];//作业名 8 int arrivetime;//作业到达时间 9 int runtime;//作业所需的运行时间 10 int usetime; //已用CPU时间 11 char stage; //进程的状态 12 int starttime; //开始时间 13 int endtime; //结束时间 14 int zztime; //作业周转时间 15 float zzxs; //周转系数 16 }JCB; 17 18 static unsigned int N=5; //作业数 19 static int current=0, current1=0; //当前时间 20 static unsigned int j=-1, j1=-1; 21 JCB job[MAX]; 22 23 void Line(); 24 void FCFS(); 25 void getValue(); 26 void getValue1(); 27 void input(); 28 void print(); 29 void choice(); 30 void SJF(); 31 32 void getValue() 33 { 34 unsigned int i; 35 current=job[0].arrivetime; 36 for(i=0; i<N; i++) 37 { 38 if(job[i].stage=='r' && current>=job[i].arrivetime) 39 { 40 if(job[i].usetime==0) 41 job[i].starttime=current; 42 job[i].stage='R'; //程序正在运行 43 job[i].usetime++; //CPU的运行时间加1 44 current++; 45 } 46 if(job[i].usetime==job[i].runtime && job[i].stage=='R') 47 { 48 j++; //用来标记有多少进程完成了 49 job[i].stage='F'; 50 job[i].endtime=current; 51 job[i].zztime=job[i].endtime-job[i].arrivetime; 52 job[i].zzxs=(float)job[i].zztime/(float)job[i].runtime; 53 } 54 if(job[i].stage!='F') 55 job[i].stage='r'; //运行完之后变回就绪态 56 if(i==N-1) //进入死循环了 57 i=-1; 58 if(j==N-1) 59 break; 60 } 61 } 62 63 void getValue1() 64 { 65 unsigned int i=0, h, rest; 66 current1=job[0].arrivetime; 67 for(; i<N; i++) 68 { 69 if(job[i].stage=='2') 70 { 71 h=0; 72 while(h<N) //判断当前时刻的这一级是否有进程 73 { 74 if(job[h].stage=='r' && current1>=job[h].arrivetime) 75 { 76 i=h; 77 h=N; 78 } 79 h++; 80 } 81 } 82 else if(job[i].stage=='3') 83 { 84 h=0; 85 while(h<N) //判断当前时刻的这一级是否有进程 86 { 87 if(job[h].stage=='2') 88 { 89 i=h; 90 h=N; 91 } 92 h++; 93 } 94 } 95 if(job[i].stage=='r' && current1>=job[i].arrivetime) 96 { 97 if(job[i].usetime==0) 98 job[i].starttime=current1; 99 job[i].stage='R'; //程序正在运行 100 job[i].usetime++; //CPU的运行时间加1 101 current1++; 102 if(job[i].usetime==job[i].runtime) 103 { 104 j1++; 105 job[i].stage='F'; 106 job[i].endtime=current1; 107 job[i].zztime=job[i].endtime-job[i].arrivetime; 108 job[i].zzxs=(float)job[i].zztime/(float)job[i].runtime; 109 } 110 else //还没完成则进入下一级 111 job[i].stage='2'; 112 } 113 else if(job[i].stage=='2') 114 { 115 job[i].stage='R'; 116 job[i].usetime+=2; 117 current1+=2; 118 if(job[i].usetime>=job[i].runtime) 119 { 120 j1++; 121 job[i].stage='F'; 122 rest=job[i].usetime-job[i].runtime; 123 current1=current1-rest; 124 job[i].endtime=current1; 125 job[i].zztime=job[i].endtime-job[i].arrivetime; 126 job[i].zzxs=(float)job[i].zztime/(float)job[i].runtime; 127 } 128 else //还没完成则进入下一级 129 job[i].stage='3'; 130 } 131 else if(job[i].stage=='3') 132 { 133 job[i].stage='R'; 134 job[i].usetime+=4; 135 current1+=4; 136 if(job[i].usetime>=job[i].runtime) 137 { 138 j1++; 139 job[i].stage='F'; 140 rest=job[i].usetime-job[i].runtime; 141 current1=current1-rest; 142 job[i].endtime=current1; 143 job[i].zztime=job[i].endtime-job[i].arrivetime; 144 job[i].zzxs=(float)job[i].zztime/(float)job[i].runtime; 145 } 146 else //还没完成则在最后一级继续轮转 147 job[i].stage='3'; 148 } 149 if(i==N-1) //进入死循环了 150 i=-1; 151 if(j1==N-1) 152 break; 153 } 154 } 155 156 void input() 157 { 158 int i, jobNum, choi; 159 printf("1.自选作业个数\n"); 160 printf("2.系统默认作业个数\n"); 161 printf("你的选择是:"); 162 scanf("%d", &choi); 163 switch(choi) 164 { 165 case 1: 166 { 167 do{ 168 printf("\nEnter process number(作业个数应在2~24之间):"); 169 scanf("%d", &jobNum); //输入作业数 170 N=jobNum; 171 printf("\n"); 172 }while(N<2 || N>24); 173 break; 174 } 175 case 2: 176 printf("\n系统默认作业个数为5"); 177 break; 178 } 179 for(i=0; i<jobNum; i++) 180 { 181 printf("\njob %d name:",i+1); 182 scanf(" "); 183 gets(job[i].name); //输入作业名 184 printf("arrive time:"); 185 scanf(" %d",&job[i].arrivetime); //输入作业达到时间 186 printf("running time:"); 187 scanf(" %d",&job[i].runtime); //输入作业执行时间 188 } 189 } 190 191 void print() 192 { 193 unsigned int i; 194 printf(" name arrivetime runtime starttime endtime zztime zzxs\n"); 195 for(i=0; i<N; i++) 196 { 197 printf("jod%d",i+1); 198 printf(" %s\t\t%d %d %d %d %d %.2f\n",job[i].name,job[i].arrivetime,job[i].runtime,job[i].starttime,job[i].endtime,job[i].zztime,job[i].zzxs); 199 } 200 } 201 void choice() 202 { 203 int mark; 204 do{ 205 printf("\n\n1. 简单轮转法;\n2. 多级反馈队列调度算法;\n3. 退出."); 206 printf("\nMake choice: "); 207 scanf("%d", &mark); 208 switch(mark) 209 { 210 case 1: 211 FCFS(); //简单轮转法
212 break; 213 case 2: 214 SJF(); //多级反馈队列调度算法
215 break; 216 case 3: 217 return; 218 default: 219 printf("\nerror!"); 220 } 221 }while(mark!=3); 222 } 223 224 void Line() 225 { 226 unsigned int a, b; 227 JCB mark; 228 current=0; current1=0; 229 j=-1; j1=-1; 230 for(a=0; a<N; a++) 231 { 232 job[a].usetime=0; 233 job[a].stage='r'; //就绪态 234 job[a].starttime=0; 235 job[a].endtime=0; 236 job[a].zztime=0; 237 job[a].zzxs=0; 238 } 239 for(a=0;a<N-1; a++) //通过到达时间整体排序 240 { 241 for(b=a+1; b<N; b++) 242 { 243 if(job[b].arrivetime<job[a].arrivetime) 244 { 245 mark=job[b]; 246 job[b]=job[a]; 247 job[a]=mark; 248 } 249 } 250 } 251 } 252 253 void FCFS() 254 { 255 Line(); 256 getValue(); //给每个作业内的相关参数赋值 257 print(); //打印出来 258 } 259 260 void SJF() 261 { 262 Line(); 263 getValue1(); 264 print(); //打印出来 265 } 266 267 void main() 268 { 269 input(); //输入 270 print(); //打印输出 271 choice(); //选择方式 272 }
4.运行结果及分析
图4.1 提示用户输入信息
图4.2 简单轮转法结果
图4.3 多级反馈队列调度算法结果
四、 实验总结
在前一次作业调度程序的基础上,改进成进程调度其实并不难,因为有那样的思维在里面,但是在做这次实验的过程中,首先理解简单轮转法和多级反馈跳读算法是很关键的,理解后顺着算法的思路编程,即使出现问题了,也能很快的找到是哪里的问题,并且不断地调试、改正,最后得到结果。