1 #include "windows.h"
2 #include <conio.h>
3 #include <stdlib.h>
4 #include <fstream.h>
5 #include <io.h>
6 #include <string.h>
7 #include <stdio.h>
8
9 void Create_ProcInfo(); // 建立进程调度需要的数据
10 void Display_ProcInfo(); // 显示当前系统全部进程的状态
11 void Scheduler_FF();
12 void Cpu_Sched();
13 void IO_Sched();
14 void NextRunProcess();
15 void DisData();
16 void DisResult();
17
18 int RunPoint; // 运行进程指针,-1时为没有运行进程
19 int WaitPoint; // 阻塞队列指针,-1时为没有阻塞进程
20 int ReadyPoint; // 就绪队列指针,-1时为没有就绪进程
21 long ClockNumber; // 系统时钟
22 int ProcNumber; // 系统中模拟产生的进程总数
23 int FinishedProc; // 系统中模拟产生的进程总数
24 int q=9;//时间片
25
26
27 //进程信息结构
28 struct ProcStruct
29 {
30 int p_pid; // 进程的标识号
31 char p_state; // 进程的状态,C--运行 R--就绪 W--组塞 B--后备 F--完成
32 int p_rserial[16]; // 模拟的进程执行的CPU和I/O时间数据序列,间隔存储,0项存储有效项数
33 int p_pos; // 当前进程运行到的序列位置
34 int p_starttime; // 进程建立时间
35 int p_endtime; // 进程运行结束时间
36 int p_cputime; // 当前运行时间段进程剩余的需要运行时间
37 int p_iotime; // 当前I/O时间段进程剩余的I/O时间
38 int p_next; // 进程控制块的链接指针
39 int p_excutetime; // 记录一次时间片内执行的时间
40 } proc[10];
41
42 ////////////////////////////////////////////////////////////////////////////
43 //
44 // 随机生成进程数量和每个CPU--I/O时间数据序列,进程数量控制在5到10之间, //
45 // 数据序列控制在6到12之间,CPU和I/O的时间数据值在5到15的范围 //
46 //
47 ////////////////////////////////////////////////////////////////////////////
48
49 void Create_ProcInfo(void )
50 {
51 int s,i,j;
52
53 srand(GetTickCount()); // 初始化随机数队列的"种子"
54 ProcNumber=((float) rand() / 32767) * 5 ; // 随机产生进程数量5~10
55
56
57 for(i=0;i<ProcNumber;i++) // 生成进程的CPU--I/O时间数据序列
58 {
59 proc[i].p_pid=((float) rand() / 32767) * 1000;
60 proc[i].p_state='B'; // 初始都为后备状态
61
62 s=((float) rand() / 32767) *6 + 2; // 产生的进程数据序列长度在6~12间
63 proc[i].p_rserial[0]=s; // 第一项用于记录序列的长度
64 for(j=1;j<=s;j++) // 生成时间数据序列
65 proc[i].p_rserial[j]=((float) rand() / 32767) *10 + 5;
66 // 赋其他字段的值
67 proc[i].p_pos=1;
68 proc[i].p_starttime=((float) rand() / 32767) *49+1; // 随机设定进程建立时间
69 proc[i].p_endtime=0;
70 proc[i].p_cputime=proc[i].p_rserial[1];
71 proc[i].p_iotime=proc[i].p_rserial[2];
72 proc[i].p_next=-1;
73 proc[i].p_excutetime=0;
74 }
75 printf("\n---------------------------\n 建立了%2d 个进程数据序列\n\n", ProcNumber);
76 DisData();
77 printf("\nPress Any Key To Continue.......");
78 _getch() ;
79 return ;
80 }
81
82 ////////////////////////////////////////////////////////////////////////
83
84 // 显示系统当前状态
85
86 ////////////////////////////////////////////////////////////////////////
87
88 void Display_ProcInfo(void)
89 { int i,n;
90
91 system("cls") ;
92 printf("时间片为%d",q);
93 printf("\n 当前系统模拟%2d 个进程的运行 时钟:%ld\n\n", ProcNumber,ClockNumber);
94
95 printf(" 就绪指针=%d, 运行指针=%d, 阻塞指针=%d\n\n",ReadyPoint,RunPoint,WaitPoint );
96 if(RunPoint!= -1)
97 {
98 printf(" 当前运行的进程 No.%d ID:%d\n", RunPoint,proc[RunPoint].p_pid);
99 printf(" %6d,%6d,%6d\n",proc[RunPoint].p_starttime,proc[RunPoint].p_rserial[proc[RunPoint].p_pos],proc[RunPoint].p_cputime);
100 printf("当前运行的进程执行的时间为%d",proc[RunPoint].p_excutetime);
101 printf("当前运行的进程执行的cpu时间为%d",proc[RunPoint].p_cputime);
102 }
103 else
104 printf(" 当前运行的进程ID:No Process Running !\n");
105
106 n=ReadyPoint;
107 printf("\n Ready Process ...... \n");
108 while(n!=-1) // 显示就绪进程信息
109 {
110 printf(" No.%d ID:%5d,%6d,%6d,%6d\n",n,proc[n].p_pid,proc[n].p_starttime,proc[n].p_rserial[proc[n].p_pos],proc[n].p_cputime );
111 n=proc[n].p_next;
112 }
113
114 n=WaitPoint;
115 printf("\n Waiting Process ...... \n");
116 while(n!=-1) // 显示阻塞进程信息
117 {
118 printf(" No.%d ID:%5d,%6d,%6d,%6d\n",n,proc[n].p_pid,proc[n].p_starttime,proc[n].p_rserial[proc[n].p_pos],proc[n].p_iotime);
119 n=proc[n].p_next;
120 }
121
122 printf("\n=================== 后备进程 ====================\n");
123 for(i=0; i<ProcNumber; i++)
124 if (proc[i].p_state=='B')
125 printf(" No.%d ID:%5d,%6d\n",i,proc[i].p_pid,proc[i].p_starttime);
126
127 printf("\n================ 已经完成的进程 =================\n");
128 for(i=0; i<ProcNumber; i++)
129 if (proc[i].p_state=='F')
130 printf("No.%d ID:%5d,%6d,%6d\n",i,proc[i].p_pid,proc[i].p_starttime,proc[i].p_endtime);
131
132 }
133
134 ////////////////////////////////////////////////////////////////////////
135
136 // 显示模拟执行的结果
137
138 ////////////////////////////////////////////////////////////////////////
139 void DisResult(void)
140 { int i;
141 printf("\n---------------------------------\n");
142 for(i=0; i<ProcNumber; i++)
143 {
144 printf("ID=%4d> %2d ",proc[i].p_pid ,proc[i].p_rserial[0] );
145 printf("%4d,%4d",proc[i].p_starttime,proc[i].p_endtime);
146 printf("\n" );
147 }
148 }
149
150 ////////////////////////////////////////////////////////////////////////
151
152 // 显示进程数据序列
153
154 ////////////////////////////////////////////////////////////////////////
155 void DisData(void)
156 { int i,j;
157
158 for(i=0; i<ProcNumber; i++)
159 {
160 printf("ID=%4d %2d > ",proc[i].p_pid ,proc[i].p_rserial[0] );
161 for(j=1; j<=proc[i].p_rserial[0];j++)
162 printf("%4d",proc[i].p_rserial[j]);
163 printf("\n" );
164 }
165 }
166 ////////////////////////////////////////////////////////////////////////
167
168 // 选择下一个可以运行的进程
169
170 ////////////////////////////////////////////////////////////////////////
171 void NextRunProcess(void)
172 {
173 if (ReadyPoint==-1) { RunPoint = -1; return;} // 就绪队列也没有等待的进程
174
175 proc[ReadyPoint].p_state ='C'; //ReadyPoint所指示的进程状态变为执行状态
176 RunPoint=ReadyPoint;
177 if( proc[ReadyPoint].p_excutetime==-1)//进程为执行成功,接着上次的cpu时间执行
178 {
179 proc[ReadyPoint].p_excutetime=0;
180 }
181 else
182 proc[ReadyPoint].p_cputime =proc[ReadyPoint].p_rserial[proc[ReadyPoint].p_pos] ;
183 ReadyPoint=proc[ReadyPoint].p_next;
184 proc[RunPoint].p_next = -1;
185
186 }
187 ////////////////////////////////////////////////////////////////////////
188
189 // CPU调度
190
191 ////////////////////////////////////////////////////////////////////////
192
193 void Cpu_Sched(void)
194 {
195 int n;
196
197 if (RunPoint == -1) // 没有进程在CPU上执行
198 { NextRunProcess(); return; }
199
200 proc[RunPoint].p_cputime--; // 进程CPU执行时间减少1个时钟单位
201 proc[RunPoint].p_excutetime++;
202 if((proc[RunPoint].p_cputime == 0&&proc[RunPoint].p_excutetime<=q))//若时间片未完,但进程已经结束
203 {
204 //printf("若时间片未完,但进程已经结束\n");
205 proc[RunPoint].p_excutetime=0;//清空运行时间
206 // 进程完成本次CPU后的处理
207 if (proc[RunPoint].p_rserial[0]==proc[RunPoint].p_pos) //进程全部序列执行完成
208 {
209 FinishedProc++;
210 proc[RunPoint].p_state ='F';
211 proc[RunPoint].p_endtime = ClockNumber;
212 RunPoint=-1; //无进程执行
213 NextRunProcess();
214 }
215 else //进行IO操作,进入阻塞队列
216 {
217 proc[RunPoint].p_pos++;
218 proc[RunPoint].p_state ='W';
219 proc[RunPoint].p_iotime =proc[RunPoint].p_rserial[proc[RunPoint].p_pos];
220 printf("进入阻塞队列\n");
221 n=WaitPoint;
222 if(n == -1) //是阻塞队列第一个I/O进程
223 WaitPoint=RunPoint;
224 else
225 { do //放入阻塞队列第尾
226 {
227 if(proc[n].p_next == -1)
228 { proc[n].p_next = RunPoint;
229 break;
230 }
231 n=proc[n].p_next;
232 } while(n!=-1) ;
233 }
234 RunPoint=-1;
235 NextRunProcess();
236 }
237 return;
238 }
239 if(proc[RunPoint].p_cputime > 0&&proc[RunPoint].p_excutetime<q)//时间片未完 程序未执行结束 继续执行
240 {
241 //printf("时间片未完 程序未执行结束 继续执行\n");
242 return;
243 }
244 //{ printf("\n RunPoint=%d,ctime=%d",RunPoint,proc[RunPoint].p_cputime);getchar();return; }
245 if(proc[RunPoint].p_cputime > 0&&proc[RunPoint].p_excutetime==q)//时间片完,但是程序未执行完 放到就绪队列尾部
246 {
247 //printf("时间片完,但是程序未执行完 放到就绪队列尾部\n");
248 int n;
249 proc[RunPoint].p_state='R'; // 进程状态修改为就绪
250 proc[RunPoint].p_next=-1;
251 proc[RunPoint].p_excutetime=-1;//清空运行时间,-1代表程序未执行完成
252 if(ReadyPoint==-1) // 就绪队列无进程
253 ReadyPoint=RunPoint;
254 else // 就绪队列有进程,放入队列尾
255 {
256 n=ReadyPoint;
257 while(proc[n].p_next!=-1) n=proc[n].p_next;
258 proc[n].p_next=RunPoint;
259 }
260 RunPoint=-1;
261 NextRunProcess(); //执行下一个进程
262 }
263
264 }
265
266
267
268 ////////////////////////////////////////////////////////////////////////
269
270 // I/O调度
271
272 ////////////////////////////////////////////////////////////////////////
273
274 void IO_Sched(void)
275 {
276 int n,bk;
277
278 if (WaitPoint==-1) return; // 没有等待I/O的进程,直接返回
279
280 proc[WaitPoint].p_iotime--; // 进行1个时钟的I/O时间
281
282 if (proc[WaitPoint].p_iotime > 0) return; // 还没有完成本次I/O
283
284 // 进程的I/O完成处理
285 if (proc[WaitPoint].p_rserial[0]==proc[WaitPoint].p_pos) //进程全部任务执行完成
286 {
287 FinishedProc++;
288 proc[WaitPoint].p_endtime = ClockNumber;
289 proc[WaitPoint].p_state ='F';
290
291 if(proc[WaitPoint].p_next==-1)
292 { WaitPoint=-1;return ;}
293 else //调度下一个进程进行I/O操作
294 {
295 n=proc[WaitPoint].p_next;
296 proc[WaitPoint].p_next=-1;
297 WaitPoint=n;
298 proc[WaitPoint].p_iotime =proc[WaitPoint].p_rserial[proc[WaitPoint].p_pos] ;
299 return ;
300 }
301 }
302 else //进行下次CPU操作,进就绪队列
303 {
304 bk=WaitPoint;
305 WaitPoint=proc[WaitPoint].p_next;
306
307 proc[bk].p_pos++;
308 proc[bk].p_state ='R'; //进程状态为就绪
309 proc[bk].p_cputime = proc[bk].p_rserial[proc[bk].p_pos];
310 proc[bk].p_next =-1;
311
312 n=ReadyPoint;
313 if(n == -1) //是就绪队列的第一个进程
314 { ReadyPoint=bk; return; }
315 else
316 { do
317 {
318 if(proc[n].p_next == -1) { proc[n].p_next = bk; break ; }
319 n=proc[n].p_next;
320 }
321 while(n!=-1);
322 }
323 }
324 return ;
325 }
326
327
328
329
330
331 ////////////////////////////////////////////////////////////////////////
332
333 // 检查是否有新进程到达,有则放入就绪队列
334
335 ////////////////////////////////////////////////////////////////////////
336
337 void NewReadyProc(void)
338 {
339 int i,n;
340
341 for(i=0; i<ProcNumber; i++)
342 {
343 if (proc[i].p_starttime == ClockNumber) // 进程进入时间达到系统时间
344 {
345 proc[i].p_state='R'; // 进程状态修改为就绪
346 proc[i].p_next=-1;
347
348 if(ReadyPoint==-1) // 就绪队列无进程
349 ReadyPoint=i;
350 else // 就绪队列有进程,放入队列尾
351 {
352 n=ReadyPoint;
353 while(proc[n].p_next!=-1) n=proc[n].p_next;
354 proc[n].p_next=i;
355 }
356 }
357 } // for
358 return;
359 }
360
361
362 ////////////////////////////////////////////////////////////////////////
363
364 // 调度模拟算法
365
366 ////////////////////////////////////////////////////////////////////////
367
368 void Scheduler_FF(void)
369 {
370 FinishedProc=0;
371 if(ProcNumber==0)
372 { printf(" 必须首先建立进程调度数据 ! \n");
373 system("cls"); return;
374 }
375
376 ClockNumber=0;// 时钟开始计时, 开始调度模拟
377 while(FinishedProc < ProcNumber) // 执行算法
378 {
379 ClockNumber++; // 时钟前进1个单位
380 NewReadyProc(); // 判别新进程是否到达
381 Cpu_Sched(); // CPU调度
382 IO_Sched(); // IO调度
383 Display_ProcInfo(); //显示当前状态
384 }
385 DisResult();
386 getch(); return;
387 }
388
389 void Change_q(void)
390 {
391 scanf("%d",&q);
392 }
393
394 ///////////////////////////////////////////////////////////////////
395
396 // 主函数
397
398 ///////////////////////////////////////////////////////////////////
399
400 int main(int argc, char* argv[])
401 {
402 char ch;
403
404 RunPoint=-1; // 运行进程指针,-1时为没有运行进程
405 WaitPoint=-1; // 阻塞队列指针,-1时为没有阻塞进程
406 ReadyPoint=-1; // 就绪队列指针,-1时为没有就绪进程
407 ClockNumber=0; // 系统时钟
408 ProcNumber=0; // 当前系统中的进程总数
409
410 system("cls") ;
411 while ( true )
412 {
413 printf("***********************************\n");
414 printf(" 1: 建立进程调度数据序列 \n") ;
415 printf(" 2: 执行调度算法\n") ;
416 printf(" 3: 显示调度结果 \n") ;
417 printf(" 4: 更改时间片 \n");
418 printf(" 5: 退出\n") ;
419 printf("***********************************\n");
420 printf( "Enter your choice (1 ~ 5): ");
421
422 do{ //如果输入信息不正确,继续输入
423 ch = (char)_getch() ;
424 } while(ch != '1' && ch != '2'&& ch != '3'&& ch != '4'&& ch != '5');
425
426 if(ch == '5') { printf( "\n");return 0; } // 选择4,退出
427 if(ch == '3') DisResult(); // 选择3
428 if(ch == '2') Scheduler_FF(); // 选择2
429 if(ch == '1') Create_ProcInfo(); // 选择1
430 if(ch == '4') Change_q();
431 _getch() ;
432 system("cls") ;
433 }
434 //结束
435 printf("\nPress Any Key To Continue:");
436 _getch() ;
437 return 0;
438 }