实验二单处理器系统的进程调度Word下载.docx
《实验二单处理器系统的进程调度Word下载.docx》由会员分享,可在线阅读,更多相关《实验二单处理器系统的进程调度Word下载.docx(10页珍藏版)》请在冰豆网上搜索。
这里的实验只使用了必不可少的信息。
一般操作系统中,无论进程控制块中信息量多少,信息都可以大致分为以下四类:
①标识信息
每个进程都要有一个惟一的标识符,用来标识进程的存在和区别于其他进程。
这个标识符是必不可少的,可以用符号或编号实现,它必须是操作系统分配的。
在后面给出的参考程序中,采用编号方式,也就是为每个进程依次分配一个不相同的正整数。
②说明信息
用于记录进程的基本情况,例如进程的状态、等待原因、进程程序存放位置、进程数据存放位置等等。
实验中,因为进程没有数据和程序,仅使用进程控制块模拟进程,所以这部分内容仅包括进程状态。
③现场信息
现场信息记录各个寄存器的内容。
当进程由于某种原因让出处理器时,需要将现场信息记录在进程控制块中,当进行进程调度时,从选中进程的进程控制块中读取现场信息进行现场恢复。
现场信息就是处理器的相关寄存器内容,包括通用寄存器、程序计数器和程序状态字寄存器等。
在实验中,可选取几个寄存器作为代表。
用大写的全局变量AX、BX、CX、DX模拟通用寄存器、大写的全局变量PC模拟程序计数器、大写的全局变量PSW模拟程序状态字寄存器。
④管理信息
管理信息记录进程管理和调度的信息。
例如进程优先数、进程队列指针等。
实验中,仅包括队列指针。
因此可将进程控制块结构定义如下:
structpcb
{intname;
intstatus;
intax,bx,cx,dx;
intpc;
intpsw;
intnext;
}
确定进程控制块内容后,要考虑的就是如何将进程控制块组织在一起。
多道程序设计系统中,往往同时创建多个进程。
在单处理器的情况下,每次只能有一个进程处于运行态,其他的进程处于就绪状态或等待状态。
为了便于管理,通常把处于相同状态的进程的进程控制块链接在一起。
单处理器系统中,正在运行的进程只有一个。
因此,单处理器系统中进程控制块分成一个正在运行进程的进程控制块、就绪进程的进程控制块组织成的就绪队列和等待进程的进程控制块组成的等待队列。
由于实验模拟的是进程调度,没有对等待队列的操作,所以实验中只有一个指向正在运行进程的进程控制块指针和一个就绪进程的进程控制块队列指针。
操作系统的实现中,系统往往在主存中划分出一个连续的专门区域存放系统的进程控制块,实验中应该用数组模拟这个专门的进程控制块区域,定义如下:
#definen10
structpcbpcbarea[n];
这样,进程控制块的链表实际上是数据结构中使用的静态链表。
进程控制块的链接方式可以采用单向和双向链表,实验中,进程控制块队列采用单向不循环静态链表。
为了管理空闲进程控制块,还应该将空闲控制块链接成一个队列。
实验中采用时间片轮转调度算法,这种算法是将进程控制块按照进入就绪队列的先后次序排成队列。
关于就绪队列的操作就是从队头摘下一个进程控制块和从队尾挂入一个进程控制块。
因此为就绪队列定义两个指针,一个头指针,指向就绪队列的第一个进程控制块;
一个尾指针,指向就绪队列的最后一个进程控制块。
实验中指向运行进程的进程控制块指针、就绪队列指针和空闲进程控制块队列指针定义如下:
intrun;
struct
{inthead;
inttail;
}ready;
intpfree;
以上是如何组织进程,下面考虑如何创建进程。
进程创建是一个原语,因此在实验中应该用一个函数实现,进程创建的过程应该包括:
①申请进程控制块:
进程控制块的数量是有限的,如果没有空闲进程控制块,则进程不能创建,如果申请成功才可以执行第②步;
②申请资源:
除了进程控制块外,还需要有必要的资源才能创建进程,如果申请资源不成功,则不能创建进程,并且归还已申请的进程控制块;
如果申请成功,则执行第三步,实验无法申请资源,所以模拟程序忽略了申请资源这一步;
③填写进程控制块:
将该进程信息写入进程控制块内,实验中只有进程标识符、进程状态可以填写,每个进程现场信息中的寄存器内容由于没有具体数据而使用进程(模拟进程创建时,需输入进程标识符字,进程标识符本应系统建立,并且是惟一的,输入时注意不要冲突),刚刚创建的进程应该为就绪态,然后转去执行第四步;
④挂入就绪队列:
如果原来就绪队列不为空,则将该进程控制块挂入就绪队列尾部,并修改就绪队列尾部指针;
如果原来就绪队列为空,则将就绪队列的头指针、尾指针均指向该进程控制块,进程创建完成。
进程创建流程图如图2.2所示。
多道程序设计的系统中,处于就绪态的进程往往是多个,它们都要求占用处理器,可是单处理器系统的处理器只有一个,进程调度就是解决这个处理器竞争问题的。
进程调度的任务就是按照某种算法从就绪进程队列中选择一个进程,让它占有处理器。
因此进程调度程序就应该包括两部分,一部分是在进程就绪队列中选择一个进程,并将其进程控制块从进程就绪队列中摘下来,另一部分工作就是分配处理器给选中的进程,也就是将指向正在运行进程的进程控制块指针指向该进程的进程控制块,并将该进程的进程控制块信息写入处理器的各个寄存器中。
图2.2进程创建流程图
实验中采用时间片轮转调度算法。
时间片轮转调度算法让就绪进程按就绪的先后次序排成队列,每次总是选择就绪队列中的第一个进程占有处理器,但是规定只能使用一个“时间片”。
时间片就是规定进程一次使用处理器的最长时间。
实验中采用每个进程都使用相同的不变的时间片。
采用时间片轮转调度算法的进程调度流程图如图2.3所示。
完成上述功能后,编写主函数进行测试:
首先建立一个就绪队列,手工输入信息建立几个进程;
然后进行进程调度;
最后将指向正在运行进程的指针指向的进程控制块的内容输出,察看结果。
图2.3进程调度流程图
5.课外题
编程实现采用优先数调度算法的进程调度。
我的实现代码(C语言):
#include<
stdio.h>
#defineN10//系统中所允许的最大进程数量
#defineSLOT5//时间片大小
//进程状态枚举
typedefenum
{
Running,//运行状态
Aready,//就绪状态
Blocking//阻塞状态
}ProStatus;
//进程控制块
typedefstruct
intname;
//进程标识符
ProStatusstatus;
//进程状态
//通用寄存器
//程序计数器寄存器
//程序状态字寄存器
//指向下一个进程的指针
}PCB;
//就绪队列指针
inthead;
//头指针
//尾指针
}Ready;
//模拟寄存器
intPSW,AX,BX,CX,DX,PC,TIME;
//PCB的静态链表
PCBpcbArea[N];
//模拟PCB区域的数组
//运行状态程序的指针
Readyready;
//空闲队列的指针
//初始化运行状态进程指针
voidInitRun()
run=-1;
//初始化就绪状态队列
voidInitReady()
ready.head=ready.tail=-1;
//初始化空闲队列
voidInitFree()
inttemp;
for(temp=0;
temp<
N-1;
temp++)
pcbArea[temp].next=temp+1;
pcbArea[temp].next=-1;
pfree=0;
//就绪队列出队
intPopReady()//返回结点在PCB区域数组的编号
if(ready.head==-1)
printf("
就绪队列为空,不能出队。
\n"
);
return-1;
temp=ready.head;
ready.head=pcbArea[temp].next;
ready.tail=-1;
returntemp;
//空闲队列出队
intPopFree()//返回结点在PCB区域数组的编号
if(pfree==-1)
空闲队列为空,不能出队。
temp=pfree;
pfree=pcbArea[temp].next;
//就绪队列入队
voidPushReady(intx)//x为入队结点的编号
ready.head=x;
ready.tail=x;
else
temp=ready.tail;
pcbArea[ready.tail].next=-1;
//创建PCB
voidCreatePCB(intx,PCBpcb)//x为要创建PCB在PCB区域数组的编号
pcbArea[x].ax=pcb.ax;
pcbArea[x].bx=pcb.bx;
pcbArea[x].cx=pcb.cx;
pcbArea[x].dx=pcb.dx;
pcbArea[x].name=pcb.name;
pcbArea[x].next=-1;
pcbArea[x].pc=pcb.pc;
pcbArea[x].psw=pcb.psw;
pcbArea[x].status=pcb.status;
//创建进程函数
voidCreate(PCBpcb)
空闲队列为空,不能创建进程。
return;
temp=PopFree();
pcb.status=Aready;
CreatePCB(temp,pcb);
PushReady(temp);
//进程调度函数
voidSchedule()
系统内没有进程可以调度。
"
temp=PopReady();
pcbArea[temp].status=Running;
TIME=SLOT;
//恢复CPU现场
AX=pcbArea[temp].ax;
BX=pcbArea[temp].bx;
CX=pcbArea[temp].cx;
DX=pcbArea[temp].dx;
PC=pcbArea[temp].pc;
PSW=pcbArea[temp].psw;
run=temp;
//将选中的进程赋给运行指针
当前运行的程序:
//输出调度结果
进程号:
%d\n"
pcbArea[run].name);
进程状态:
pcbArea[run].status);
寄存器内容:
\nAX\tBX\tCX\tDX\tPC\tPSW\n"
%d\t%d\t%d\t%d\t%d\t%d\n"
pcbArea[run].ax,pcbArea[run].bx,pcbArea[run].cx,pcbArea[run].dx,pcbArea[run].pc,pcbArea[run].psw);
voidmain()
PCBtmp_pcb;
请输入进程号,以负数为结束(进程号应保持唯一)。
\n\n按任意键进入输入模式:
getchar();
InitRun();
InitReady();
InitFree();
请开始输入进程号:
while
(1)
scanf("
%d"
&
temp);
if(temp<
0)
break;
tmp_pcb.name=temp;
tmp_pcb.ax=temp;
tmp_pcb.bx=temp;
tmp_pcb.cx=temp;
tmp_pcb.dx=temp;
tmp_pcb.pc=temp;
tmp_pcb.psw=temp;
Create(tmp_pcb);
Schedule();