操作系统课程设计报告.docx
《操作系统课程设计报告.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计报告.docx(48页珍藏版)》请在冰豆网上搜索。
操作系统课程设计报告
操作系统课程设计报告
时间:
2011-12-26~2012-1-6
地点:
信息技术实验中心
计算机科学与技术专业
2009级1班10号
李盛闻
2011-1-6
一、课程设计的目的和意义
本次操作系统课程设计的主要任务是进行系统级的程序设计。
本课程设计是操作系统原理课程的延伸。
通过该课程设计,使学生更好地掌握操作系统各部分结构、实现机理和各种典型算法,加深对操作系统的设计和实现思路的理解,培养学生的系统设计和动手能力,学会分析和编写程序。
课程设计的实施将使学生在以下几个方面有所收获:
(1)加深对操作系统原理的理解,提高综合运用所学知识的能力;
(2)培养学生自主查阅参考资料的习惯,增强独立思考和解决问题的能力;
(3)通过课程设计,培养严谨的科学态度和协作精神。
二、进程调度算法模拟
1设计目的
(1)要求学生设计并实现模拟进程调度的算法:
时间片轮转及先来先服务。
(2)理解进程控制块的结构。
(3)理解进程运行的并发性。
(4)掌握进程调度算法。
2设计要求
在多道程序运行环境下,进程数目一般多于处理机数目,使得进程要通过竞争来使用处理机。
这就要求系统能按某种算法,动态地把处理机分配给就绪队列中的一个进程,使之运行,分配处理机的任务是由进程调度程序完成的。
一个进程被创建后,系统为了便于对进程进行管理,将系统中的所有进程按其状态,将其组织成不同的进程队列。
于是系统中有运行进程队列、就绪队列和各种事件的进程等待队列。
进程调度的功能就是从就绪队列中挑选一个进程到处理机上运行。
进程调度的算法有多种,常用的有优先级调度算法、先来先服务算法、时间片轮转算法。
进程是程序在处理机上的执行过程。
进程存在的标识是进程控制块(PCB),进程控制块结构如下:
typedefstructnode
{
charname[10];//进程标识符
intprio;//进程优先数
intround;//进程时间轮转时间片
intcputime;//进程占用CPU时间
intneedtime;//进程到完成还需要的时间
intcount;//计数器
charstate;//进程的状态
structnode*next//链指针
}PCB;
系统创建一个进程,就是由系统为某个程序设置一个PCB,用于对该进程进行控制和管理,进程任务完成,由系统收回其PCB,该进程便消亡。
每个进程可以有三个状态:
运行状态、就绪状态和完成状态。
用C语言、C++或者Java语言编写一个程序实现进程调度的算法,模拟进程调度的过程,加深对进程控制块概念和进程调度算法的理解。
本任务要求完成时间片轮转及先来先服务两个算法。
3时间片轮转算法模拟
时间片轮转调度,具体做法是调度程序每次把CPU分配给就绪队列首进程使用一个时间片。
当这个时间片结束时,就强迫一个进程让出处理器,让它排列到就绪队列的尾部,等候下一轮调度。
实现这种调度要使用一个间隔时钟。
当一个进程开始运行时,就将时间片的值置入间隔时钟内,当发生间隔时钟中断时,就表明该进程连续运行的时间已超过一个规定的时间片。
此时,中断处理程序就通知处理器调度进行处理器的切换工作。
3.1设计要求
(1)进程的调度采用时间片轮转算法;
(2)设计三个链队列,分别用来表示运行队列、就绪队列和完成队列。
(3)用户输入进程标识符以及进程所需的时间,申请空间存放进程PCB信息。
(4)输出的格式和上面的运行结果分析中的格式相同。
3.2程序设计思想
在计算机中系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把CPU分配给队首进程,并令其执行一个时间片;
时间片的大小从几ms到几百ms。
当执行的时间片用完,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的末尾;
然后再把处理机分配给就绪队列中给定的时间内均能获得一时间片的处理机执行时间。
3.3程序结构
typedefstructpcb{
charname[10];//进程标识符
intpArriveTime;//到达时间
intpRunTime;//估计运行时间
intround;//进程时间轮转时间片
intcputime;
//进程占用CPU时间
intneedtime;//进程到完成还要的时间
intcount;//计数器
charstate;//进程的状态
structpcb*next;//链指针
}PCB;
PCB*finish,*ready,*tail,*run;//队列指针
PCBhead_input;
intN;//进程数
3.4主要算法程序
3.4.1轮转法插入
voidinsert2(PCB*p2)
{
tail->next=p2;//将新的PCB插入在当前就绪队列的尾
tail=p2;
p2->next=NULL;
}
3.4.2轮转法创建进程PCB
voidcreate2()
{
PCB*p;
inti,time,n;
charna[10];
ready=NULL;
finish=NULL;
run=NULL;
printf("输入进程名及所需时间\n");
for(i=1;i<=N;i++)
{
p=(PCB*)malloc(sizeof(PCB));
scanf("%s",na);
scanf("%d",&time);
strcpy(p->name,na);
p->cputime=0;
p->needtime=time;
p->count=0;//计数器
p->state='W';
p->round=3;
if(ready!
=NULL)
insert2(p);
else
{
p->next=ready;
ready=p;
tail=p;
}
}
3.4.3时间片轮转法
voidroundrun()
{
while(run!
=NULL)
{
run->cputime=run->cputime+1;
run->needtime=run->needtime-1;
run->count=run->count+1;
if(run->needtime==0)//运行完将其变为完成态,插入完成队列
{
run->next=finish;
finish=run;
run->state='F';
run=NULL;
if(ready!
=NULL)
firstin();//就绪对列不空,将第一个进程投入运行
}
else
if(run->count==run->round)//如果时间片到
{
run->count=0;//计数器置0
if(ready!
=NULL)//如就绪队列不空
{
run->state='W';//将进程插入到就绪队列中等待轮转
insert2(run);
firstin();//将就绪对列的第一个进程投入运行
}
}
prt();//输出进程信息
}
}
3.5流程图
3.6运行结果
4.先来先服务算法模拟
4.1设计要求
(1)进程的调度采用先来先服务算法。
(2)设计三个链队列,分别用来表示运行队列、就绪队列和完成队列。
(3)用户输入进程标识符以及进程所需的时间,申请空间存放进程PCB信息。
(4)输出的格式和上面的运行结果分析中的格式相同。
先来先服务:
按照进程进入就绪队列的先后次序来分配处理器。
先进入就绪队列的进程优先被挑选,运行进程一旦占有处理器将一直运行下去直到运行结束或被阻塞,这是一种非剥夺式调度。
4.2程序设计思想
(1)用C语言的调度。
(2)每个用来标识进程的进程控制块PCB可用结构来描述,包括以下字段:
✧进程标识数ID。
✧进程优先数PRIORITY,并规定优先数越大的进程,其优先权越高。
✧进程已占用CPU时间CPUTIME。
✧进程还需占用的CPU时间ALLTIME。
当进程运行完毕时,ALLTIME变为0。
✧进程的阻塞时间STARTBLOCK,表示当进程再运行STARTBLOCK个时间片
后,进程将进入阻塞状态。
✧进程被阻塞的时间BLOCKTIME,表示已阻塞的进程再等待BLOCKTIME个
时间片后,将转换成就绪状态。
✧进程状态STATE。
✧队列指针NEXT,用来将PCB排成队列。
(3)优先数改变的原则:
✧进程在就绪队列中呆一个时间片,优先数增加1。
✧进程每运行一个时间片,优先数减3。
(4)为了清楚地观察每个进程的调度过程,程序应将每个时间片内的进程的情况显示出来,包括正在运行的进程,处于就绪队列中的进程和处于阻塞队列中的进程。
4.3程序结构
typedefstructPCB//定义进程控制块
{
charID[3];//进程号
charname[10];//进程名
charstate;//运行状态
intarrivetime;//到达时间
intstarttime;//进程开始时间
intfinishtime;//进程结束时间
intservicetime;//服务时间
floatturnaroundtime;//周转时间
floatweightedturnaroundtime;//带权周转时间
structPCB*next;//指向下个进程
}pcb;
inttime;//计时器
intn;//进程个数
pcb*head=NULL,*p,*q;//进程链表指针
4.4主要算法程序
voidrun_fcfs(pcb*p1)//运行未完成的进程
{
time=p1->arrivetime>time?
p1->arrivetime:
time;
p1->starttime=time;
printf("\n现在时间是%d,开始运行作业%s\n",time,p1->name);
time+=p1->servicetime;
p1->state='T';
p1->finishtime=time;
p1->turnaroundtime=p1->finishtime-p1->arrivetime;
p1->weightedturnaroundtime=p1->turnaroundtime/p1->servicetime;
printf("ID到达时间开始时间服务时间完成时间周转时间带权周转时间\n");
printf(""%s%6d%10d%10d%8d%10.1f%10.2f\n"",
p1->ID,p1->arrivetime,p1->starttime,p1->servicetime,p1->finishtime,
p1->turnaroundtime,p1->weightedturnaroundtime);
}
voidfcfs()//找到当前未完成的进程
{
inti,j;
p=head;
for(i=0;i{
if(p->state=='F')
{
q=p;//标记当前未完成的进程
run_fcfs(q);
}
p=p->next;
}
}
voidgetInfo()//获得进程信息并创建进程
{
intnum;
printf("\n作业个数:
");
scanf("%d",&n);
for(num=0;num{
p=(pcb*)malloc(sizeof(pcb));
printf("依次输入:
\nID进程名到达时间服务时间\n");
scanf("%s\t%s\t%d\t%d",&p->ID,&p->name,&p->arrivetime,&p->servicetime);
if(head==NULL){head=p;q=p;time=p->arrivetime;}
if(p->arrivetime
q->next=p;
p->starttime=0;
p->finishtime=0;
p->turnaroundtime=0;
p->weightedturnaroundtime=0;
p->next=NULL;
p->state='F';
q=p;
}
}
voidmain()
{
printf("先来先服务算法模拟");
getInfo();
p=head;
fcfs();
}
4.5流程图
4.6运行结果
三、主存空间的回收与分配
1设计目的
主存是中央处理器能直接存取指令和数据的存储器,能否合理地利用主存,在很大程度上将影响到整个计算机系统的性能。
主存分配是指在多道作业和多进程环境下,如何共享主存空间。
主存回收是指当作业执行完毕或进程运行结束后将主存空间归还给系统。
主存分配与回收的实现是与主存储器的管理方式有关。
本次设计主要是为了帮助学生深入理解主存空间的分配与回收的几种算法。
(1)掌握最先适应分配算法
(2)掌握最优适应分配算法(3)掌握最坏适应分配算法
2设计要求
用户提出内存空间请求,系统根据申请者要求,按照最先适应分配算法的分配策略分析内存空间的使用情况,找出能满足请求的空闲区,分给申请者,当程序执行完毕时,系统要收回它所占用的内存空间。
建立空闲数据文件,空闲区数据文件包括若干行,每行有两个字段:
起始地址、内存块大小(均为整数),各字段以逗号隔开。
下面是一个空闲区数据文件的示例:
0,10
10,08
18,10
28,06
34,10
44,09
读取空闲区数据文件,建立空闲区表并在屏幕上显示空闲内存状态,空闲区表记录了可供分配的空闲内存的起始地址和大小,用标志位指出该分区是否是未分配的空闲区。
接收用户的内存申请,格式为:
作业名、申请空间的大小。
按照内存分配算法中的一种方法选择一个空闲区,分割并分配,修改空闲区表,填写内存已分配区表(起始地址、长度、标志位),其中标志位的一个作用是指出该区域分配给哪个作业。
进程结束后回收内存。
本次设计要求完成如下算法:
(1)设计一个内存分配回收的程序使用最先适应分配算法
(2)设计一个内存分配回收的程序使用最优适应分配算法
(3)设计一个内存分配回收的程序使用最坏适应分配算法
用户提出内存空间请求,系统根据申请者要求,选择上述算法的一种分配策略分析内存空间的使用情况,找出合适的空闲区,分给申请者,当进程执行完毕时,系统收回它所占用的内存空间。
创建空闲区表:
空闲区表的结构如下:
typedefstructnode{
intstart;
intlength;
chartag[20];
}job;
3模拟算法的实现
3.1程序结构
structtable{
charjob;//作业标号
floataddress;//分区起始地址
floatlength;//分区长度,单位为字节
intflag;//分区表的状态位
structtable*FRlink;//前向指针
structtable*RElink;//后向指针
}*free_table=NULL,*place;//已分配分区表,空闲分区表
typedefstructtableFRtable;
FRtable*init(FRtable*tb)
{
tb->FRlink=NULL;
tb->job=nil;
tb->address=1064;
tb->length=1664;
tb->flag=0;
tb->RElink=NULL;
returntb;
}
3.2程序设计思想
先创建空间分区链表;
为作业分配分区空间,空间大小为x;
采用CFF时定位到上次找到的合适空间分区的下个空间分区;
当搜索到的空间大小小于或等于x+minisize时,将空间全部分配给作业;
当搜索到的空间大小大于或等于x+minisize时,先将空间划分,再分配给作业。
3.3主要算法程序
3.3.1为作业分配空间
voidallocate(charjob,floatxk,intchoice)
{
FRtable*tb,*link;
intk=0;floattemp=600;
if(free_table->FRlink==NULL&&free_table->RElink==NULL)
{//给首个作业分配空间,改写分区链表
free_table->job=job;
free_table->length=xk;
free_table->flag=1;
if(xk{
tb=getspace(FRtable);
free_table->RElink=tb;
tb->FRlink=free_table;
tb->job=nil;
tb->address=1064+xk;
tb->length=maxisize-xk;
tb->flag=0;
}
if(choice==2)
{//链接成循环链表
free_table->FRlink=tb;
tb->RElink=free_table;
place=tb;
}
else
{
free_table->FRlink=NULL;
if(xkRElink=NULL;
}
k=1;
}
else
{
if(2==choice)tb=place;//采用CFF时将ta定位到上次找到的合适空间分区的下个空间分区
elsetb=free_table;
while(tb!
=NULL)
{
if(3==choice)
{
while(tb!
=NULL)
{
if(tb->length>=xk&&tb->flag==0)
if(tb->length{place=tb;temp=tb->length;}//选择最适合空间
tb=tb->RElink;
}
tb=place;
}
if(tb->length>=xk&&tb->flag==0)
if(tb->length-xk<=minisize)
{//当搜索到的空间大小<=xk+minisize时,将空间全部分配给作业
tb->job=job;
tb->flag=1;
place=tb->RElink;
k=1;
break;
}
else
{//当搜索到的空间大小>xk+minisize时,将空间划分,再分配给作业
link=getspace(FRtable);
link->length=tb->length-xk;
tb->job=job;
tb->length=xk;
tb->flag=1;
link->RElink=tb->RElink;
if(NULL!
=tb->RElink)tb->RElink->FRlink=link;
tb->RElink=link;
link->FRlink=tb;
link->job=nil;
link->address=tb->address+xk;
link->flag=0;
place=link;
k=1;
break;
}
tb=tb->RElink;
}
}
if(0==k)
{
printf(">>空间申请失败!
\n");
return;
}
}
3.3.2回收作业所占用的空间
voidreclaim(charjob,intchoice)
{
intbool1=0,bool2=0;
FRtable*tb,*link;
tb=free_table;
if(2==choice)link=tb;
elselink=NULL;
do
{
if(job==tb->job&&1==tb->flag)break;
tb=tb->RElink;
if(tb==link)
{
printf("\n>>抱歉,不存在作业%c!
\n",job);
return;
}
}while(tb!
=link);
bool1=(NULL==tb->FRlink||tb->FRlink==tb->RElink)?
1:
tb->FRlink->flag;
bool2=(NULL==tb->RElink||tb->FRlink==tb->RElink)?
1:
tb->RElink->flag;
if(bool1&&bool2)
{
tb->job=nil;
tb->flag=0;
}
elseif((NULL==tb->FRlink||1==tb->FRlink->flag)&&0==tb->RElink->flag)
{
link=tb->RElink;
tb->job=nil;
tb->length+=link->length;
tb->flag=0;
tb->RElink=link->RElink;
if(NULL!
=link->RElink)link->RElink->FRlink=tb;
free(link);
}
elseif(0==tb->FRlink->flag&&1==tb->RElink->flag)
{
link=tb->FRlink;
link->length+=tb->length;
link->RElink=tb->RElink;
tb->RElink->FRlink=link;
if(free_table==tb)free_table=link;
free(tb);
}
elseif(0==tb->FRlink->flag&&0==tb->RElink->flag)
{
link=tb->FRlink;
link->length=link->length+tb->length+tb->RElink->length;
link->RElink=tb->RElink->RElink;
if(NULL!
=tb->RElink->RElink)tb->RElink->RElink->FRlink=link;
if(free_table==tb)free_table=link;
free(tb);
free(tb->RElink);
}
}
3.3.3显示空间分区链表
voiddisplay(