资源描述
计算机操作系统课程设计报告
60
2020年4月19日
文档仅供参考,不当之处,请联系改正。
《操作系统原理》
实 验 报 告
院 (部): 管理工程学院
专 业:信息管理与信息系统
实验项目:实验一 二 三 五
班 级:信管102
姓 名:张凤丹
学 号: 021418
目 录
引 言 4
实验一、模拟进程创立、终止、阻塞、唤醒原语 6
实验目的: 6
实验内容: 6
实验步骤: 7
实验代码: 7
程序运行结果及分析 12
实验感想: 13
实验二、模拟进程调度功能 14
实验目的: 14
实验内容: 14
实验步骤: 14
实验代码: 15
程序运行结果及分析 19
实验感想: 20
实验三:模拟动态分区首次适应分配和回收算法 20
实验目的: 20
实验内容: 20
实验步骤: 20
实验代码: 21
程序运行结果及分析 27
实验感想: 28
实验五:模拟使用银行家算法判断系统的状态 28
实验目的: 28
实验步骤: 28
实验代码: 28
程序运行结果及分析 33
实验感想: 34
引 言
操作系统是信息管理与信息系统专业一门重要的专业理论课程,了解和掌握操作系统的基本概念、功能和实现原理,对认识整个计算机系统的工作原理十分重要。
操作系统实验是操作系统课程的一个重要组成部分,经过试验环节的锻炼使同学们不但能够对以前的所学过的基础知识加以巩固,同时能够经过上机实验,对操作系统的抽象理论知识加以理解,最终达到融会贯通的目的,因此,实验环节是同学们理解、掌握操作系统基本理论的一个重要环节。
本实验指导书,根据教材中的重点内容设定了相应的实验题目,由于实验课程的学时有限,我们规定了必做题目和选做题目,其中必做题目必须在规定的上机学时中完成,必须有相应的预习报告和实验报告。选做题目是针对有能力或感兴趣的同学利用课余时间或上机学时的剩余时间完成。
实验一、模拟进程创立、终止、阻塞、唤醒原语
实验目的:
经过设计并调试创立、终止、阻塞、唤醒原语功能,有助于对操作系统中进程控制功能的理解,掌握操作系统模块的设计方法和工作原理。
实验内容:
1、设计创立、终止、阻塞、唤醒原语功能函数。
2、设计主函数,采用菜单结构(参见后面给出的流程图)。
3、设计“显示队列”函数,目的能将就绪、阻塞队列中的进程信息显示在屏幕上,以供随时查看各队列中进程的变化情况。
实验步骤:
其中:
进程名用P1,P2标识。
优先级及运行时间:为实验题目二做准备。
状态为:就绪、运行、阻塞,三种基本状态。
指针:指向下一个PCB。
1、进程PCB中应包含以下内容:
进程名
优先级
运行时间
状态
指针
2、系统总体结构:
开始
系统主菜单
1…创立
2…阻塞
3…唤醒
4…终止
5…显示
0…退出
请输入您需要的功能(0-5):
输入选择=?
5
4
3
2
1
0
退出
创立
阻塞
唤醒
终止
显示
结束
实验代码:
#include <stdio.h>
#include<string.h>
struct PCB
{
char name[4];
int priority;
int runtime;
};
void main()
{
int x,t;
int a=0;
int k=0,r=1,i=0,j=0;//k为就绪队列总数,r堵塞队列总数
char name[4];
struct PCB pcb[10];
struct PCB pcb1[10];
struct PCB pcb2[10];
printf("---------------------菜单---------------------\n\n\n");
printf("0----退出系统\n");
printf("1----创立进程\n");
printf("2----堵塞进程\n");
printf("3----唤醒进程\n");
printf("4----终止进程\n");
printf("5----显示进程\n");
printf("------------------------------------------------\n");
strcpy(pcb1[0].name,"s");//堵塞队列
pcb1[0].priority = 2;
pcb1[0].runtime = 3;
//printf("%s %d %d",pcb1[0].name,pcb1[0].priority,pcb1[0].runtime);
while(1)
{
printf("请输入你的选择:");
scanf("%d",&x);
if(x==0)
break;
if(x==1)
{
printf("-----------------创立进程---------------\n");
printf("进程名:");
scanf("%s",&pcb[k].name);
printf("优先级:");
scanf("%d",&pcb[k].priority);
printf("运行时间:");
scanf("%d",&pcb[k].runtime);
k=k+1;
}
if(x==2)
{
printf("-----------------堵塞进程---------------\n");
printf("请输入要查找的进程:");
scanf("%s",name);
for(j=0;j<=k;j++)
{
if(strcmp(pcb[j].name,name)==0)
{
t=j;
strcpy(pcb2[a].name,pcb[t].name);
pcb2[a].priority = pcb[t].priority;
pcb2[a].runtime = pcb[t].runtime;
strcpy(pcb1[r].name,pcb2[a].name);
pcb1[r].priority = pcb2[a].priority;
pcb1[r].runtime = pcb2[a].runtime;
r=r+1;
a=a+1;
for(i=t;i<=k;i++)
{
strcpy(pcb[i].name,pcb[i+1].name);
pcb[i].priority = pcb[i+1].priority;
pcb[i].runtime = pcb[i+1].runtime;
}
k=k-1;
printf("将就绪序列调度为运行:");
for(i=0;i<a;i++)
printf("%s %d %d\n",pcb2[i].name,pcb2[i].priority,pcb2[i].runtime);
printf("堵塞进程:\n");
for(j=0;j<r;j++)
printf("%s %d %d\n",pcb1[j].name,pcb1[j].priority,pcb1[j].runtime);
break;
}
else
printf("该进程已是堵塞进程!\n");
break;
}
}
if(x==3)
{
printf("-----------------唤醒进程---------------\n");
printf("请输入要唤醒的进程:");
scanf("%s",name);
for(i=0;i<r;i++)
{
if(strcmp(pcb1[i].name,name)==0)
{
t=i;
strcpy(pcb[k].name,pcb1[t].name);
pcb[k].priority = pcb1[t].priority;
pcb[k].runtime = pcb1[t].runtime;
k=k+1;
for(j=t;j<r;j++)
{
strcpy(pcb1[j].name,pcb1[j+1].name);
pcb1[j].priority = pcb1[j+1].priority;
pcb1[j].runtime = pcb1[j+1].runtime;
}
r=r-1;
printf("就绪进程:\n");
for(j=0;j<k;j++)
printf("%s %d %d\n",pcb[j].name,pcb[j].priority,pcb[j].runtime);
printf("堵塞进程:\n");
for(j=0;j<r;j++)
printf("%s %d %d\n",pcb1[j].name,pcb1[j].priority,pcb1[j].runtime);
break;
}
else
printf("该堵塞进程为空,不能唤醒进程!\n");
break;
}
}
//for(j=0;j<k;j++)
//printf("%s %d %d\n",pcb[j].name,pcb[j].priority,pcb[j].runtime);
if(x==4)
{
printf("-----------------终止进程---------------\n");
printf("请输入你要终止的进程:");
scanf("%s",name);
for(i=0;i<k;i++)
{
if(strcmp(pcb[i].name,name)==0)
{
t=i;
for(j=t;j<k;j++)
{
strcpy(pcb[j].name,pcb[j+1].name);
pcb[j].priority = pcb[j+1].priority;
pcb[j].runtime = pcb[j+1].runtime;
}
k=k-1;
}
if(strcmp(pcb1[i].name,name)==0)
{
t=i;
for(j=t;j<r;j++)
{
strcpy(pcb1[j].name,pcb1[j+1].name);
pcb1[j].priority = pcb1[j+1].priority;
pcb1[j].runtime = pcb1[j+1].runtime;
}
r=r-1;
}
}
printf("就绪进程:\n");
for(j=0;j<k;j++)
printf("%s %d %d\n",pcb[j].name,pcb[j].priority,pcb[j].runtime);
printf("堵塞进程:\n");
for(j=0;j<r;j++)
printf("%s %d %d\n",pcb1[j].name,pcb1[j].priority,pcb1[j].runtime);
}
if(x==5)
{
printf("-----------------显示进程---------------\n");
printf("就绪进程:\n");
for(j=0;j<k;j++)
printf("%s %d %d\n",pcb[j].name,pcb[j].priority,pcb[j].runtime);
printf("堵塞进程:\n");
for(j=0;j<r;j++)
printf("%s %d %d\n",pcb1[j].name,pcb1[j].priority,pcb1[j].runtime);
}
}
}
程序运行结果及分析
1) 运行结果
实验感想:
经过设计并调试创立、终止、阻塞、唤醒原语功能,加深了对操作系统中进程控制功能的理解,而且掌握操作系统模块的设计方法和工作原理。更重要的是理解了操作系统的调度方法是就绪-运行-堵塞-唤醒-结束的过程。
实验二、模拟进程调度功能
实验目的:
经过本实验,进一步掌握进程调度的功能和实现原理。
实验内容:
1、 设计进程调度功能,至少模拟两种以上调度算法。如:优先级调度算法、时间片调度算法等。
2、 进程调度功能作为一个函数scheduler,加入到实验题目一中。
3、 进程调度程序从就绪队列中挑选进程,若队列为空,应显示“无就绪进程无法调度”的提示信息。
4、 若选上一个进程,以显示:进程名、状态、时间片、优先级等信息表示一个进程被执行。若运行完,应删除相应PCB。
实验步骤:
1、 在实验题目一中的主菜单中加入一个菜单项:6 调度,选择该菜单项后,系统进入进程调度。
2、 进程调度的结构:
进程调度子菜单
0---------返回主菜单
1---------优先级调度
2---------时间片调度
请选择您需要的功能选项:
读入选择=》x
=》x
X=??
= 0 = 2
转时间片调度算法
转优先级调度算法
返回上级菜单
= 1
实验代码:
#include <stdio.h>
#include<string.h>
void priority();
void time();
struct PCB
{
char name[4];
int priority;
int runtime;
};
struct PCB pcb[5];
int q=5;
void main()
{
int p,i;
strcpy(pcb[0].name,"p1");//序列队列,优先级由高到低为1,2,3.....
pcb[0].priority = 2;
pcb[0].runtime = 3;
strcpy(pcb[1].name,"p2");//序列队列
pcb[1].priority = 3;
pcb[1].runtime = 2;
strcpy(pcb[2].name,"p3");//序列队列
pcb[2].priority = 1;
pcb[2].runtime = 4;
strcpy(pcb[3].name,"p4");//序列队列
pcb[3].priority = 5;
pcb[3].runtime = 6;
strcpy(pcb[4].name,"p5");//序列队列
pcb[4].priority = 4;
pcb[4].runtime = 5;
printf("------------------------------进程调度子菜单------------------------------\n");
printf(" 0---------退出系统\n");
printf(" 1---------优先级调度\n");
printf(" 2---------时间片调度\n");
printf("\n\n显示所有进程\n");
for(i=0;i<5;i++)
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
printf("请选择您需要的功能选项:");
scanf("%d",&p);
printf("***********************\n");
while(1)
{
if(p==0)
break;
switch(p)
{
//case 0:
//break;
case 1:
printf("优先级调度算法\n");
priority();
break;
case 2:
printf("时间片调度算法\n");
time();
break;
}
printf("请选择您需要的功能选项:");
scanf("%d",&p);
printf("***********************\n");
}
}
void priority()
{
int i,j;
int t=0,r=0;
//int q=5;
char name[2]=" ";
for(i=0;i<q-1;i++)
for(j=i;j<q;j++)
{
if(pcb[i].priority>pcb[j].priority)
{
strcpy(name,pcb[i].name);
strcpy(pcb[i].name,pcb[j].name);
strcpy(pcb[j].name,name);
t=pcb[i].priority;
pcb[i].priority=pcb[j].priority;
pcb[j].priority=t;
r=pcb[i].runtime;
pcb[i].runtime=pcb[j].runtime;
pcb[j].runtime=r;
}
}
printf("按优先级高低进行排序\n");
for(i=0;i<q;i++)
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
printf("***********************\n");
printf("显示优先级最高的进程\n");
printf("%s %d %d\n",pcb[0].name,pcb[0].priority,pcb[0].runtime);
for(i=0;i<q;i++)
{
strcpy(pcb[i].name,pcb[i+1].name);
pcb[i].priority = pcb[i+1].priority;
pcb[i].runtime = pcb[i+1].runtime;
}
printf("***********************\n");
printf("使最高优先级进程处于执行状态(撤销该进程)\n");
for(i=0;i<q-1;i++)//撤销进程
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
q=q-1;
}
void time()
{
int i,j,t;
//int q=5;
for(i=0;i<q;i++)
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
for(i=0;i<q;i++)
{
pcb[i].runtime = pcb[i].runtime-1;
}
printf("***********************\n");
printf("将每个执行进程的执行时间减去一个时间片。\n");
for(i=0;i<q;i++)
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
for(i=0;i<q;i++)
{
if(pcb[i].runtime<=0)
{ t=i;
for(j=t;j<q;j++)
{
strcpy(pcb[j].name,pcb[j+1].name);
pcb[j].priority = pcb[j+1].priority;
pcb[j].runtime = pcb[j+1].runtime;
}
q=q-1;
}
}
printf("***********************\n");
printf("将进行结束的进程撤销。\n");
for(i=0;i<q;i++)
{
printf("%s %d %d\n",pcb[i].name,pcb[i].priority,pcb[i].runtime);
}
}
程序运行结果及分析
实验感想:
经过本实验,我进一步掌握进了程调度的功能和实现原理。熟练掌握了两种进程调度算法的应用,相信这对以后进一步学习操作系统、信息系统的开发都有很大的好处。
实验三:模拟动态分区首次适应分配和回收算法
实验目的:
经过本实验,可加深理解动态分区分配、回收程序的功能和具体实现,特别是对回收分区的合并的理解。
实验内容:
1、 设计动态分区首次适应分配、回收算法。
2、 设计“未分配区说明表”,格式为:
序号
始址
长度
状态
1
60k
200
1
0
3、 设计“已分配区说明表”,格式为:
作业名
始址
长度
状态
0
0
4、 设计显示程序,将“未分配区说明表”和“已分配区说明表”的内容,显示在屏幕上。
初始分配从一个空闲区分配起,回收时要合并空区。
实验步骤:
1、 系统要求分配一个分区时,应输入:作业名、作业长度。
2、 回收一个分区时,应输入:回收的作业名。回收的分区请注意是否需要进行合并。
实验代码:
#include <STDIO.H>
#include <STDLIB.H>
int MAX_SEGMENT=10;//最大碎片值
struct Partition //分区表目
{
int Par_Size; //分区大小
int Par_No; //分区序号或者名字
int Addr; //分区地址
int IsUse; //分区使用情况,0表示空闲,1表示使用
Partition *pri; //前向指针
Partition *next; //后向指针
};
Partition * Int()//函数,返回Partition类型指针
{ //初始化空闲分区表
Partition *list,*H,*H1;
list=(struct Partition *)malloc(sizeof(struct Partition));//malloc申请动态分配空间
list->next=NULL;
H=list;
if(!list)
{
printf("\n错误,内存初始化分配失败!程序结束");
exit(1);
}
H1=(struct Partition *)malloc(sizeof(struct Partition));
printf("请预先输入分区总大小(以KB为单位):");
scanf("%d",&H1->Par_Size);
H1->Addr=0;
H1->Par_No=0;
H1->IsUse=0;
H1->pri=H;
H1->next=NULL;
H->next=H1;////list--->H1
return list;
}
Partition * InitFP()
{ //初始化已分配分区表
Partition *FP,*F,*H;
int i;
FP=(struct Partition *)malloc(sizeof(struct Partition));
FP->next=NULL;
H=FP;
for(i=0;i<10;i++) //已分配区先暂定分配十个表目
{
F=(struct Partition *)malloc(sizeof(struct Partition));
if(!F)
{
printf("\n错误,内存分配失败!程序结束");
exit(1);
}
F->Par_Size=0;
F->Addr=0;
F->Par_No=0;
F->IsUse=0;
F->next=NULL;
H->next=F;
F->pri=H;
H=H->next;
}
return FP;
}
Partition * New_Process( Partition *list, Partition *FP)
{ //为新的进程分配资源
Partition *H,*P,*H1;
int Size,Name,L;
H=list;
H1=FP->next;
H=H->next;
printf("请输入新作业的名称和大小(整数)\n");
printf("作业名称:");
scanf("%d",&Name);
printf("作业大小(整数):");
scanf("%d",&Size);
while(H)
{
if(!H) //表目已查完,无法分配
{
printf("\n已无空闲分区,本次无法分配!");
return list;
}
else{
if(H->IsUse==0) //空表目
//if(H->Par_Size>=Size) //大小满足,空闲分区大小》要分配的大小
if(H->Par_Size>=Size) //大小满足,
{
bool temp=false;
if((H->Par_Size-Size)<=MAX_SEGMENT){//空闲分区大小-要分配的大小<碎片值,会产生碎片,将整块内存大小分配出去,
Size=H->Par_Size;//分配的大小为整块内存
temp=true;//会产生碎片
}
//其它情况就分配大小为请求大小,不会产生碎片,
L=H->Addr;//保存空闲分地址
if(temp){
printf("该次内存分配会产生碎片,将整块内存大小%d分配出去!",Size);
}else{
printf("该次内存分配不会产生碎片");
}
break;
}
}
H=H->next; //否则,继续往下查找
}
if(H)
{
if(H->Par_Size>Size) //大小满足,空闲分区大小》要分配的大小
{
P=(struct Partition *)malloc(sizeof(struct Partition)); //分配新的表目,处理一条数据,分配一次内存
P->IsUse=1;
P->Addr=L;//指向空闲分区地址
P->next=H; //修改指针
H->pri->next=P;
P->pri=H->pri;
H->pri=P;
P->Par_Size=Size;//分配大小为要请求分配的大小
P->Par_No=Name;//名称
H->Par_Size-=Size; //修改空闲分区,H所指区块大小减Size
H->Addr+=Size;//H所指区块地址加Size
}else
{
H->IsUse=1; //大小相等的,把当前表项设置空表目
}
while(H1)
{
if(H1->IsUse==0)
{
H1->Par_No=Name;
H1->Par_Size=Size;
H1->Addr=L;//保存已分配地址
H1->IsUse=1;//在已分配表中设置为已分配
break;
}
H1=H1->next;
}
}else
printf("所申请资源已大过系统所拥有的,请重新输入!\n");
return list;
}
Partition *Reclaim( Partition *list, Partition *FP)
{ //结束作业,资源回收,No为作业名,回收内存
Partition * H1,*H2,*H3,*HF;//H1为释放区,H2为后分区,H3为前分区
int No; //作业名
H1=list;
HF=FP;//可有可无?
H1=H1->next;
HF=FP->next;
printf("请输入您想结束的作业名:");
scanf("%D",&No);
while(HF)//对已分配表进行操作
{
if(HF->Par_No==No)
{
HF->IsUse=0; //标志为空表目
break;//这时保存着HF所指分区的信息
}
HF=HF->next;
}
if(!HF) //如果找不到该作业,则提示出错
printf("所输入的作业名称不正确,请重新输入!");
else{
while(H1)//对空闲表进行操作
{
if(H1->Par_No==No)
{
H1->IsUse=0; //标志为空表目
printf("内存回收成功");
break;
}
H1=H1->next;
}
H2=H1->next;//后分区
H3=H1->pri;//前分区
if(H2&&H2->IsUse==0) //后接分区为空闲
{
if(H2->next==NULL) //判断后接分区是否为尾结点
{
H1->Par_Size+=H2->Par_Size; //把H2合并到H1
H1->next=NULL;
free(H2);
printf("已回收%d大小内存",H1->Par_Size);
}else //后分区不为空闲,表示已经被使用
{
H1->Par_Size+=H2->Par_Size;
H1->next=H2->next;
H2->next->pri=H1;
free(H2);
printf("已回收%d大小内存",H1->Par_Size);
}
}
if(H3&&H3->IsUse==0) //前分区为空闲分区,则合并去前分区
{
H3->Par_Size+=H1->Par_Size;
H3->next=H1->next;
if(H1->next!=NULL) //若H1为尾结点
H1->next->pri=H3;
free(H1);
printf("已回收%d大小内存",H1->Par_Size);
}
}
return list;
}
void Print( Partition *list, Partition *FP)
{ //输出已分配分区和空闲分区
Partition *H1,*H2;
H1=list->next;
H2=FP;
H2=H2->next;
printf("**************************************************\n");
printf("****************总分配分区表*******************\n");
printf("分区序号 大小 开始地址 状态\n");
while(H1)
{
printf("%d %d %d",H1-
展开阅读全文