一、 实验目的
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 多级反馈队列调度算法结果
四、 实验总结
在前一次作业调度程序的基础上,改进成进程调度其实并不难,因为有那样的思维在里面,但是在做这次实验的过程中,首先理解简单轮转法和多级反馈跳读算法是很关键的,理解后顺着算法的思路编程,即使出现问题了,也能很快的找到是哪里的问题,并且不断地调试、改正,最后得到结果。