上机实验指导书
课程名称 操作系统
主撰人 刘天波
审核人 栾方军
沈阳建筑大学信息学院
2014 年3月
课程名称:操作系统
上机学时:16
适用专业:计算机科学与技术
先修课程:C语言
一、 上机实验总体目标
操作系统是计算机教学中最重要的环节之一,也是计算机专业学生的一门重要的专业课程。操作系统质量的好坏,直接影响整个计算机系统的性能和用户对计算机的使用。一个精心设计的操作系统能极大地扩充计算机系统的功能,充分发挥系统中各种设备的使用效率,提高系统工作的可靠性。由于操作系统涉及计算机系统中各种软硬件资源的管理,内容比较繁琐,具有很强的实践性。要学好这门课程,必须把理论与实践紧密结合,才能取得较好的学习效果。
培养计算机专业的学生的系统程序设计能力,是操作系统课程的一个非常重要的环节。通过操作系统上机实验,可以培养学生程序设计的方法和技巧,提高学生编制清晰、合理、可读性好的系统程序的能力,加深对操作系统课程的理解。使学生更好地掌握操作系统的基本概念、基本原理、及基本功能,具有分析实际操作系统、设计、构造和开发现代操作系统的基本能力。
二、 上机实验课时分配
序号 |
上机实验项目 |
实验类型 |
每组人数 |
上机学时 |
1 |
进程调度模拟实验 |
设计 |
|
4 |
2 |
银行家算法模拟实验 |
设计 |
|
4 |
3 |
存储器管理模拟实验 |
设计 |
|
4 |
4 |
文件操作的模拟实验 |
设计 |
|
4 |
三、 上机实验环境
硬件:CPU P4 2.4Hz,内存512MB,硬盘40GB或以上
软件:Windows XP Professional简体中文版,Visual C++ 6.0或Turbo C 2.0
四、 参考书
1、《计算机操作系统》,汤小丹、哲屏凤、汤子瀛编,西安电子科技大学出版社,2007年
2、《计算机操作系统教程》,张尧学、史美林编著,清华大学出版社,2000年
3、《操作系统原理》,庞丽萍著,华中理工大学出版社,1988年
【实验目的】
1. 理解进程的概念,熟悉进程的组成;
2. 用高级语言编写和调试一个进程调度程序,以加深对进程调度算法的理解。
【实验准备】
1. 几种进程调度算法
l 短进程优先调度算法
l 高优先权优先调度算法
l 先来先服务调度算法
l 基于时间片的轮转调度算法
2. 进程的组成
l 进程控制块(PCB)
l 程序段
l 数据段
3. 进程的基本状态
l 就绪W(Wait)
l 执行R(Run)
l 阻塞B(Block)
【实验内容】
1. 例题
设计一个有 N个进程共行的进程调度程序。
进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。进程的运行时间以时间片为单位进行计算。每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。重复以上过程,直到所要进程都完成为止。
2. 调度算法的流程图
3. 部分源程序
jingchendiaodu.cpp
#include "stdio.h"
#include
#include
#define getpch(type) (type*)malloc(sizeof(type))
#define NULL 0
struct pcb { /* 定义进程控制块PCB */
char name[10];
char state;
int super;
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->super)>(ready->super))) /*优先级最大者,插入队首*/
{
p->link=ready;
ready=p;
}
else /* 进程比较优先级,插入适当的位置中*/
{
first=ready;
second=first->link;
while(second!=NULL)
{
if((p->super)>(second->super)) /*若插入进程比当前进程优先数大,*/
{ /*插入到当前进程前面*/
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;
clrscr(); /*清屏*/
printf("\n 请输入进程号?");
scanf("%d",&num);
for(i=0;i { printf("\n 进程号No.%d:\n",i); p=getpch(PCB); printf("\n 输入进程名:"); scanf("%s",p->name); printf("\n 输入进程优先数:"); scanf("%d",&p->super); printf("\n 输入进程运行时间:"); scanf("%d",&p->ntime); printf("\n"); p->rtime=0;p->state='w'; p->link=NULL; sort(); /* 调用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 super \t ndtime \t runtime \n"); printf("|%s\t",pr->name); printf("|%c\t",pr->state); printf("|%d\t",pr->super); 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(); /* 调用destroy函数*/ else { (p->super)--; p->state='w'; sort(); /*调用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(); } 4. 实验题目 l 编写并调试一个模拟的进程调度程序,采用“最高优先数优先”调度算法对五个进程进行调度。“最高优先数优先”调度算法的基本思想是把CPU分配给就绪队列中优先数最高的进程。静态优先数是在创建进程时确定的,并在整个进程运行期间不再改变。动态优先数是指进程的优先数在创建进程时可以给定一个初始值,并且可以按一定原则修改优先数。例如在进程获得一次CPU后就将其优先数减少1。或者,进程等待的时间超过某一时限时增加其优先数的值,等等。 l 编写并调试一个模拟的进程调度程序,采用“轮转法”调度算法对五个进程进行调度。轮转法可以是简单轮转法、可变时间片轮转法,或多队列轮转法。简单轮转法的基本思想是:所有就绪进程按 FCFS排成一个队列,总是把处理机分配给队首的进程,各进程占用CPU的时间片相同。如果运行进程用完它的时间片后还为完成,就把它送回到就绪队列的末尾,把处理机重新分配给队首的进程。直至所有的进程运行完毕。 【思考题】 1. 几种进程调度算法各有什么优缺点? 【实验目的】 1. 理解死锁的概念; 2. 用高级语言编写和调试一个银行家算法程序,以加深对死锁的理解。 【实验准备】 1. 产生死锁的原因 l 竞争资源引起的死锁 l 进程推进顺序不当引起死锁 2.产生死锁的必要条件 l 互斥条件 l 请求和保持条件 l 不剥夺条件 l 环路等待条件 3.处理死锁的基本方法 l 预防死锁 l 避免死锁 l 检测死锁 l 解除死锁 【实验内容】 1. 实验原理 银行家算法是从当前状态出发,逐个按安全序列检查各客户中谁能完成其工作,然后假定其完成工作且归还全部贷款,再进而检查下一个能完成工作的客户。如果所有客户都能完成工作,则找到一个安全序列,银行家才是安全的。与预防死锁的几种方法相比较,限制条件少,资源利用程度提高了。缺点:该算法要求客户数保持固定不变,这在多道程序系统中是难以做到的;该算法保证所有客户在有限的时间内得到满足,但实时客户要求快速响应,所以要考虑这个因素;由于要寻找一个安全序列,实际上增加了系统的开销.Banker algorithm 最重要的一点是:保证操作系统的安全状态!这也是操作系统判断是否分配给一个进程资源的标准!那什么是安全状态?举个小例子,进程P 需要申请8个资源(假设都是一样的),已经申请了5个资源,还差3个资源。若这个时候操作系统还剩下2个资源。很显然,这个时候操作系统无论如何都不能再分配资源给进程P了,因为即使全部给了他也不够,还很可能会造成死锁。若这个时候操作系统还有3个资源,无论P这一次申请几个资源,操作系统都可以满足他,因为操作系统可以保证P不死锁,只要他不把剩余的资源分配给别人,进程P就一定能顺利完成任务。 2.实验题目 设计五个进程{P0,P1,P2,P3,P4}共享三类资源{A,B,C}的系统,{A,B,C}的资源数量分别为10,5,7。进程可动态地申请资源和释放资源,系统按各进程的申请动态地分配资源。要求程序具有显示和打印各进程的某一时刻的资源分配表和安全序列;显示和打印各进程依次要求申请的资源号以及为某进程分配资源后的有关资源数据。 3.算法描述 我们引入了两个向量:Resourse(资源总量)、Available(剩余资源量) 以及两个矩阵:Claim(每个进程的最大需求量)、Allocation(已为每个进程分配的数量)。它们共同构成了任一时刻系统对资源的分配状态。 向量模型: R1 R2 R3 矩阵模型: R1 R2 P1 P2 P3 这里,我们设置另外一个矩阵:各个进程尚需资源量(Need),可以看出 Need = Claim – Allocation 因此,我们可以这样描述银行家算法: 设Request[i]是进程Pi的请求向量。如果Request[i , j]=k,表示Pi需k个Rj类资源。当Pi发出资源请求后,系统按下述步骤进行检查: (1) if (Request[i]<=Need[i]) goto (2); (3) 系统试探性把要求资源分给Pi(类似回溯算法)。并根据分配修改下面数据结构中的值。 Available[i] = Available[i] – Request[i] ; Allocation[i] = Allocation[i] + Request[i]; Need[i] = Need[i]-Request[i]; (4) 系统执行安全性检查,检查此次资源分配后,系统是否处于安全状态。若安全,才正式将资源分配给进程以完成此次分配;若不安全,试探方案作废,恢复原资源分配表,让进程Pi等待。 系统所执行的安全性检查算法可描述如下: 设置两个向量:Free、Finish 工作向量Free是一个横向量,表示系统可提供给进程继续运行所需要的各类资源数目,它含有的元素个数等于资源数。执行安全算法开始时,Free = Available.标记向量Finish是一个纵向量,表示进程在此次检查中中是否被满足,使之运行完成,开始时对当前未满足的进程做Finish[i] = false;当有足够资源分配给进程(Need[i]<=Free)时,Finish[i]=true,Pi完成,并释放资源。 (1)从进程集中找一个能满足下述条件的进程Pi ① Finish[i] == false(未定) ② Need[i] <= Free (资源够分) (2)当Pi获得资源后,认为它完成,回收资源: Free = Free + Allocation[i] ; Finish[i] = true ; Go to step(1); 试探此番若可以达到Finish[0..n]:=true,则表示系统处于安全状态,然后再具体为申请资源的进程分配资源。否则系统处于不安全状态。 我们还举银行家的例子来说明:设有客户A、B、C、D,单一资源即为资金(R)。 下列状态为安全状态,一个安全序列为:C->D->B->A A 1 6 B 1 5 C 2 4 D 4 7 Available = (2) ; Resourse = (10) ; 4.参考程序 #include /*ass为进程已分配资源,need为最大需求,r为各种资源的个数*/ int main() { int i,ct; init(); { void init() { scanf("%d",&r[i]); { printf("p%d:",i); { void output() { { int small(int x[],int y[]) { int bankalgo() { { stack[++top]=current; process number:5 【思考题】 1.银行家算法有什么缺点? 【实验目的】 1. 通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解; 2. 熟悉虚存管理的各种页面淘汰算法; 3. 通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。 【实验准备】 1.虚拟存储器的管理方式 l 段式管理 l 页式管理 l 段页式管理 2.页面置换算法 l 先进先出置换算法 l 最近最久未使用置换算法 l Clock置换算法 l 其他置换算法 【实验内容】 1. 实验题目 设计一个请求页式存储管理方案。并编写模拟程序实现之。产生一个需要访问的指令地址流。它是一系列需要访问的指令的地址。为不失一般性,你可以适当地(用人工指定地方法或用随机数产生器)生成这个序列,使得 50%的指令是顺序执行的。25%的指令均匀地散布在前地址部分,25%的地址是均匀地散布在后地址部分。为简单起见。页面淘汰算法采用 FIFO页面淘汰算法,并且在淘汰一页时,只将该页在页表中抹去。而不再判断它是否被改写过,也不将它写回到辅存。 2. 具体做法 产生一个需要访问的指令地址流;指令合适的页面尺寸(例如以 1K或2K为1页);指定内存页表的最大长度,并对页表进行初始化;每访问一个地址时,首先要计算该地址所在的页的页号,然后查页表,判断该页是否在主存——如果该页已在主存,则打印页表情况;如果该页不在主存且页表未满,则调入一页并打印页表情况;如果该页不足主存且页表已满,则按 FIFO页面淘汰算法淘汰一页后调入所需的页,打印页表情况;逐个地址访问,直到所有地址访问完毕。 3. 存储管理算法的流程图 【思考题】 1. 几种页面置换算法各有什么优缺点? 【实验目的】 1. 了解文件系统的原理; 2. 用高级语言编写和调试一个简单的文件系统,模拟文件管理的工作过程。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。 【实验准备】 1.文件的逻辑结构 l 顺序文件 l 索引文件 l 索引顺序文件 l 直接文件和哈希文件 2.外存分配方式 l 连续分配 l 链接分配 l 索引分配 【实验内容】 1. 实验要求 要求设计一个 n个用户的文件系统,每次用户可保存m个文件,用户在一次运行中只能打开一个文件,对文件必须设置保护措施,且至少有Create、delete、open、close、read、write等命令。 2. 实验题目 l 设计一个10个用户的文件系统,每次用户可保存10个文件,一次运行用户可以打开5个文件。 l 程序采用二级文件目录(即设置主目录[MFD])和用户文件目录(UED)。另外,为打开文件设置了运行文件目录(AFD)。 l 为了便于实现,对文件的读写作了简化,在执行读写命令时,只需改读写指针,并不进行实际的读写操作。 3. 算法与框图 因系统小,文件目录的检索使用了简单的线性搜索。文件保护简单使用了三位保护码:允许读写执行、对应位为 1,对应位为0,则表示不允许读写、执行。程序中使用的主要设计结构如下:主文件目录和用户文件目录( MFD、UFD)打开文件目录( AFD)(即运行文件目录)。 M D F 用户名 文件目录指针 用户名 文件目录指针 U F D 文件名 保护码 文件长度 文件名 A F D 打开文件名 打开保护码 读写指针 【思考题】 1.什么是逻辑文件,什么是物理文件,它们有什么区别? 实验2 银行家算法模拟实验
else error(“over request”);
(2) if (Request[i]<=Available[i]) goto (3);
else wait();
#include
#include
#define N 10
#define M 10
typedef struct{
int ip;
int able[N];
int visited[N];
int remain[M];
}WorkNode; /*工作节点*/
int ass[N][M],need[N][M],r[M],top=-1,pnum=0,rnum=0;
/*currnet为当前工作节点*/
WorkNode stack[N],current;
void add(int [],int []); /*进程完成,释放资源*/
int small(int [],int []); /*已有的资源是否能满足最大请求*/
void init(); /*初始化*/
void output();/*输出堆栈中的一种可能*/
int bankalgo(); /*银行家算法主要部分,回溯法*/
for(i=0;i
current.able[++current.ip]=i;
if(current.ip==-1)
printf("it is unsafe\n");
}
else if(ct=bankalgo())
printf("\it is safe,and it has %d solutions\n",ct);
else printf("\nit is unsafe\n");
return 0;
}
int i,j,sum=0;
clrscr();
printf("process number:");
scanf("%d",&pnum);
printf("resource number:");
scanf("%d",&rnum);
printf("resource series:");
for(i=0;i
printf("assined matrix:");
for(i=0;i
for(j=0;j
}
printf("needed matrix:\n");
for(i=0;i
for(j=0;j
}
memset(current.visited,0,sizeof(current.visited) );
{ for(i=0;i
for(j=0;j
current.remain[i]=r[i]-sum;
sum=0;
}
current.ip=-1;
}
int i;
for(i=0;i<=top;i++)
printf("p%d,",stack[i].able[stack[i].ip]);
printf("\n");
}
void add(int x[],int y[])
int i;
for(i=0;i
}
int i;
for(i=0;i
}
if(i==rnum)return 1;
return 0;
}
int i,ct=0;
while(1)
current.visited[current.able[current.ip]]=1;
add(current.remain,ass[current.able[current.ip]]);
current.ip=-1;
for(i=0;i
current.able[++current.ip]=i;
if(current.ip==-1)
{
if(top==pnum-1){
output();
ct++;
}
else if(top<0)break;
current=stack[top--];
while(current.ip==0)current=stack[top--];
current.ip--;
}
}
return ct;
}
测试结果如下
resource number:4
resource series:6 3 4 2
assined matrix:p0:3 0 1 1
p1:0 1 0 0
p2:1 1 1 0
p3:1 1 0 1
p4:0 0 0 0
needed matrix:
p0:1 1 0 0
p1:0 1 1 2
p2:3 1 0 0
p3:0 0 1 0
p4:2 1 1 0
p3-->p4-->p0-->p2-->p1
p3-->p4-->p0-->p1-->p2
p3-->p0-->p4-->p2-->p1
p3-->p0-->p4-->p1-->p2
p3-->p0-->p2-->p4-->p1
p3-->p0-->p2-->p1-->p4
p3-->p0-->p1-->p4-->p2
p3-->p0-->p1-->p2-->p4
it is safe,and it has 8 solutions实验3 存储器管理模拟实验
实验4 文件操作的模拟实验