进程调度算法的模拟
【实验目的】
- 理解进程概念。
- 深入理解系统如何管理进程。
- 掌握常用进程调度算法的实现。
【实验原理/实验基础知识】
- 进程概念
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
由PCB、程序、数据构成。PCB是进程存在的唯一标识,是操作系统对进程进行控制、管理和调度的依据。
- 进程三状态
1、就绪态:已具备运行条件,但因为其它进程正占用CPU ,所以暂时不能运行而等待分配CPU的状态;
2、运行态:已分配到CPU ,正在处理器上执行时的状态;
3、阻塞态:因等待某种事件发生(例如I/O)而暂时不能运行的状态。处于该状态的进程尚不具备运行条件,即使CPU空闲,它也无法使用。
- 进程调度的任务
进程调度的任务包括:保存处理机的现场信息、按某种算法选取进程并将处理器分配给进程。
- 常用进程调度算法
- 先来先服务First-Come First-Served:按提交的先后次序进行调度。
- 短作业优先 Shortest Job First:选择运行时间最小的进行调度。
- 响应比高优先 Highest Response Ratio First:选择响应比高的作业投入运行。
- 最短剩余时间优先Shortest Remaining Time First: 选择剩余运行时间最小的进行调度,属于抢占式调度方式。
- 时间片轮转法RR(Round Robin):每次把CPU 分配给就绪队列首进程使用一个时间片,当这个时间片结束时,就强迫该进程让出CPU,让它排列到就绪队列的尾部,等候下一轮调度。
- 优先级法Priority Scheduling
- 静态优先级调度算法:优先级在整个过程中保持不变。
- 动态优先级调度算法:优先级会随进程的执行改变。
【实验环境】VMware Workstation、RedHat
【实验步骤】
编写程序,采用动态优先级调度算法实现进程调度。要求由用户输入进程PCB信息,优先级大的进程优先分配CPU,且优先级每运行一个CPU时间单位就降低一级。
进程状态分为W(就绪)、R(运行)、F(完成)。就绪进程在获得CPU后只能运行一个时间单位。运行后,将进行PCB中已占用CPU的时间加1。如果运行一个CPU时间单位后,进程的已占用时间达到了所需要的运行时间,则撤销该进程。如果运行一个CPU时间单位后,进程的已占用CPU时间尚未达到所需要的运行时间,即进程还需要继续运行,则此时将进程的优先数减1(即降低一级),然后把它插入就绪队列并等待CPU。
每进行一次调度,程序就输出一次运行进程和就绪队列中所有进程的信息,以便进行检查。重复以上过程,直到所有进程运行完毕为止。
代码如下
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define getpch(type) (type*)malloc(sizeof(type))
#define NULL 0
struct pcb {
char name[10];
char state;
int nice;
int ntime;
int rtime;
struct pcb* link; }
*ready=NULL,*p;
typedef struct pcb PCB;
sort() {
PCB *first, *second;
int insert=0;
if((ready==NULL)||((p->nice)>(ready->nice))) {
p->link=ready;ready=p;
}else{
first=ready;
second=first->link;
while(second!=NULL){
if((p->nice)>(second->nice)){
p->link=second;
first->link=p;
second=NULL;
insert=1;
}else{
first=first->link;
second=second->link; } }
if(insert==0) first->link=p; } }
input() {
int i,num;
printf("\n 请输入进程数");
scanf("%d",&num);
for(i=0;i<num;i++){
printf("\n 进程号No.%d:\n",i);
p=getpch(PCB);
printf("\n 输入进程名:");
scanf("%s",p->name);
printf("\n 输入进程优先数:");
scanf("%d",&p->nice);
printf("\n 输入进程运行时间:");
scanf("%d",&p->ntime);
printf("\n");
p->rtime=0;p->state='w';
p->link=NULL;
sort(); } }
int space() {
int l=0;
PCB* pr=ready;
while(pr!=NULL){
l++;
pr=pr->link; }
return(l); }
disp(PCB *pr){
printf("\n qname \t state \t nice \t ndtime \t runtime \n");
printf("|%s\t",pr->name); printf("|%c\t",pr->state); printf("|%d\t",pr->nice);
printf("|%d\t",pr->ntime); printf("|%d\t",pr->rtime); printf("\n"); }
check(){
PCB* pr;
printf("\n **** 当前正在运行的进程是:%s",p->name);
disp(p);
pr=ready;
printf("\n ****当前就绪队列状态为:\n");
while(pr!=NULL){
disp(pr);
pr=pr->link; } }
destroy(){
printf("\n 进程 [%s] 已完成.\n",p->name);
free(p); }
running(){
(p->rtime)++;
if(p->rtime==p->ntime) destroy();
else{
(p->nice)--;
p->state='w';
sort(); } }
main(){
int len,h=0;
char ch;
input();
len=space();
while((len!=0)&&(ready!=NULL)){ ch=getchar();
h++;
printf("\n The execute number:%d \n",h);
p=ready;
ready=p->link;
p->link=NULL;
p->state='R';
check();
running();
printf("\n 按任一键继续......");
ch=getchar(); }
printf("\n\n 进程已经完成.\n");
ch=getchar(); }
运行结果
【实验报告】
填写《上机实验报告》。
【思考题】
- 实验中要求完成的调度算法是抢占式还是非抢占式?
答:抢占式
- 如何将上述调度算法改为固定优先数调度算法?
答:需要确定每个进程的优先数。在固定优先数调度算法中,每个进程都有一个固定的优先数,这个优先数在进程创建时确定,并且在进程的整个运行期间保持不变。因此,需要为每个进程设定一个固定的优先数。然后按照优先数调度进程。在调度进程时,按照每个进程的优先数进行调度。优先数越高的进程将获得更多的处理机时间,而优先数较低的进程将等待更长的时间。需要注意避免优先数冲突。在设定优先数时,需要确保不会出现两个进程的优先数相同的情况,以免出现冲突。