《操作系统》
实验指导书
实验项目
一、实验目的
(一)进程同步模拟实验
实验类型
实验学时
验证
4
通过实验模拟读者和写者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进
程同步的问题的了解。具体如下:
1)掌握基本的同步互斥算法,理解读者和写者模型;
2)了解 windows 中多线程(多进程)的并发执行机制,线程(进程)间的同步和互斥;
3)学习使用 windows 中基本的同步对象,掌握相应的 API。
二、设备与环境
1. 硬件设备:PC 机一台
2. 软件环境:安装 Windows 操作系统或者 Linux 操作系统,并安装相关的程序开发环境,
如 C \C++\Java 等编程语言环境。
三、实验要求
用高级语言编写和调试一个采用“读写平等”策略的“读者-写者”问题的模拟程序。利用模
拟用信号量机制实现读者和写者问题:通过用户控制读进程和写进程,反应读者和写者问题中所
涉及的进程的同步与互斥。
1. 问题描述:
模拟用信号量机制实现读者和写者问题,即有两组并发进程:读者和写者,共享一组数据区,
进行读写操作,要求任一时刻“写者”最多只允许一个,而“读者”则允许多个。
2. 规则说明:
允许多个读者同时执行读操作;
不允许读者、写者同时操作;
不允许多个写者同时操作。
四、实验设计参考
1. 分析读者和写者的相互关系:
1)“读-写”互斥,即不能同时有一个读者在读,同时去有一个写者在写;
2)“写-写”互斥,即不能有两个写者同时进行写操作;
3)“读-读”允许,即可以有两个以上的读者同时进行读操作。
2. 采用的信号量机制
1)Wmutex 表示读写的互斥信号量,初值: Wmutex =1;
2)公共变量 Rcount 表示“正在读”的进程数,初值:Rcount =0;
3)Rmutex:表示对 Rcount 的互斥操作,初值:Rmutex=1。
main()
{int Wmutex=1;
int Rmutex=1;
int Rcount=0;
cobegin
read1();
…
readi();
write1();
V(Rmutex);
while (false);
写者进程:
writem()
{
P
P(Wmutex);
写
读者进程:
Readn()
{ P(Rmutex);
Rcount++;
if
(Wmutex);
(Rcount==1)
V(Rmutex);
读
P(Rmutex);
1
…
writej();
coend}
Rcount--;
if
V(Wmutex);
(Rcount==0)
}
V(Wmutex);
设计中首先用户输入读者个数 r_num 和写者个数 w_num,来模拟用信号量机制实现
r_num 个读者和 w_num 个写者同时处理一个数据区的问题。所有的读者或写者对操作的申请和
完成都是由用户控制,更容易反映读者和写者问题的规律。
3. 算法流程图见下页
4. 数据结构说明
int r_num;//读者个数
int w_num;//写者个数
int Wmutex=1;//表示允许写或允许读
int Rcount=0;//表示正在读的进程数
int Rmutex=1;//表示对 Rcount 的互斥操作
int r[10]={0,0,0,0,0,0,0,0,0,0};//表示读者的状态,1 表示正在读
int w[10]={0,0,0,0,0,0,0,0,0,0};//表示写者的状态,1 表示正在写
int w_wait[11]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};//表示等待队列,0-9 表示写者,10 时需引入读者的等
int r_wait[11]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};//读者的等待队列,0-9 表示对应的读者,-1 为空
待队列,-1 表示空
5. 模块说明
四组 P、V 函数:
1)写者进程由 3 个函数组成
void write_p(int i);//模拟写者对 Wmutex 的 P 操作,同时也作为写者进程的入口
void write(int i);//开始写操作
void write_v(int i);//模拟写者对 Wmutex 的 V 操作,写操作完成的时候调用
2)读者进程由 8 个函数组成
void radd_p(int i);//模拟读之前对 Rmutex 的 P 操作,同时也作为读者进程的入口
void radd(int i);//Rcount 加 1
void read_p(int i);//模拟读者对 Wmutex 的 P 操作
void radd_v(int i);//模拟读之前对 Rmutex 的 V 操作
void read(int i);//读
void rsub_p(int i);//模拟读之后对 Rmutex 的 P 操作,读操作完成的时候调用
void rsub(int i);//Rcount 减 1
void read_v(int i);//模拟读者对 Wmutex 的 V 操作
void rsub_v(int i);//模拟读之后对 Rmutex 的 V 操作
2
开始
输入读者和
写者个数
用户进行
选择操作
多进程?
Y
No.1 写者?
N
读 者 进 程 同
时 进 行 读 操
作,写者依次
进入等待
用户进行
选择操作
结 束
N
运行进程
Y
第一个写者进
行写操作,后
面进程依次进
入等待状态
【注意事项】
1. 遵守实验室的规章制度,维护实验教学秩序,不得随意拆卸、移动计算机。
2. 注意使用模块化程序设计方法,逐模块进行编写和调试。
3. 实验报告撰写要求结构清晰、描述准确逻辑性强;实验过程中,同学之间可以进行讨论互相
提高,但绝对禁止抄袭。
3
实验项目
一、实验目的
(二)进程调度模拟实验
实验类型
实验学时
设计
4
设计一个有N个进程并行的进程调度程序
二、设备与环境
1. 硬件设备:PC 机一台
2. 软件环境:安装 Windows 操作系统或者 Linux 操作系统,并安装相关的程序开发环境,
如 C \C++\Java 等编程语言环境。
三、实验要求
要求学生熟练掌握最高优先级优先的进程调度算法,并使用 C 语言编写程序模拟若干个进
程的进程调度过程。
1 .问题描述:
进程调度算法:采用最高优先级优先的调度算法。
每个进程有一个进程控制块( PCB)表示。进程控制块可以包含进程名、优先级、到达时
间、需要运行时间、已用 CPU 时间、进程状态等等。
进程的运行时间以时间片为单位进行计算。
每个进程的状态是就绪 W(Wait)、运行 R(Run)、或完成 F(Finish)三种状态之一。
进程名、优先级、需要运行时间通过键盘输入。
就绪进程获得 CPU 后都只能运行一个时间片。用已占用 CPU 时间加 1 来表示。
运行一个时间片后,进程的已占用 CPU 时间已达到所需要的运行时间,则撤消该进程,否
则将进程的优先级减 1(即降低一级),然后把它插入就绪队列等待 CPU。
每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检
查。
重复以上过程,直到所有进程都完成为止。
2. 调度算法的流程图:
4
【注意事项】
1. 遵守实验室的规章制度,维护实验教学秩序,不得随意拆卸、移动计算机。
2. 注意使用模块化程序设计方法,逐模块进行编写和调试。
3. 独立完成实验,根据实验测试数据和结果认真完成实验报告。
实验项目
一、实验目的
(三)基本存储器管理实验
实验类型
实验学时
设计
2
理解分区式存储管理的基本原理,熟悉分区分配和回收算法。
即理解在不同的存储管理方式下,如何实现主存空间的分配与回收;并掌握动态分区分配方
式中的数据结构和分配算法及动态分区存储管理方式及其实现过程。
二、设备与环境
1. 硬件设备:PC 机一台
2. 软件环境:安装 Windows 操作系统或者 Linux 操作系统,并安装相关的程序开发环境,
如 VC \VC++\Java 等编程语言环境。
三、实验原理
实验要求使用可变分区存储管理方式,分区分配中所用的数据结构采用空闲分区表和空闲分
区链来进行,分区分配中所用的算法采用首次适应算法、最佳适应算法、最差适应算法三种算法
来实现主存的分配与回收。同时,要求设计一个实用友好的用户界面,并显示分配与回收的过程。
同时要求设计一个实用友好的用户界面,并显示分配与回收的过程。
A、主存空间分配
(1)首次适应算法
在该算法中,把主存中所有空闲区按其起始地址递增的次序排列。在为作业分配存储空间时,
从上次找到的空闲分区的下一个空闲分区开始查找,直到找到第一个能满足要求的空闲区,从中
划出与请求的大小相等的存储空间分配给作业,余下的空闲区仍留在空闲区链中。
(2)最佳适应算法
在该算法中,把主存中所有空闲区按其起始地址递增的次序排列。在为作业分配存储空间时,
从上次找到的空闲分区的下一个空闲分区开始查找,直到找到一个能满足要求的空闲区且该空闲
区的大小比其他满足要求的空闲区都小,从中划出与请求的大小相等的存储空间分配给作业,余
下的空闲区仍留在空闲区链中
(3)最坏适应算法
在该算法中,把主存中所有空闲区按其起始地址递增的次序排列。在为作业分配存储空间时,
从上次找到的空闲分区的下一个空闲分区开始查找,直到找到一个能满足要求的空闲区且该空闲
区的大小比其他满足要求的空闲区都大,从中划出与请求的大小相等的存储空间分配给作业,余
下的空闲区仍留在空闲区链中。
B、主存空间回收
当一个作业执行完成撤离时,作业所占的分区应该归还给系统。归还的分区如果与其它空闲
区相邻,则应合成一个较大的空闲区,登记在空闲区说明链中,此时,相邻空闲区的合并问题,
要求考虑四种情况:
2. 释放区下邻空闲区(低地址邻接)
3. 释放区上邻空闲区(高地址邻接)
4. 释放区上下都与空闲区邻接
5. 释放区上下邻都与空闲区不邻接
5
四、实验要求
1. 模拟操作系统的主存分配,运用可变分区的存储管理算法设计主存分配和回收程序,并不
实际启动装入作业。
2. 采用首次适应法、最佳适应法、最坏适应法分配主存空间。
3. 当一个新作业要求装入主存时,必须查空闲区表,从中找出一个足够大的空闲区。若找到
的空闲区大于作业需要量,这是应把它分成二部分,一部分为占用区,加一部分又成为一
个空闲区。
4. 当一个作业撤离时,归还的区域如果与其他空闲区相邻,则应合并成一个较大的空闲区,
登在空闲区表中。
5. 运行所设计的程序,输出有关数据结构表项的变化和内存的当前状态。
五、实验设计参考
1.算法流图
main 函数的流程图
选择算法 a
a=1,首次适应算法
a=2,最佳适应算法
a=3,最坏适应算法
初始化 first 和 end
整理分区序号
显示空闲分区链
选择操作 i
i=1,分配空间函数 a
i=0,退出程序
i=2,回收空间函数
结束
6
分配空间的流程图
分配空间函数
a=1
a=2
a=3
输入申请内存
大小
初始化 q,使它指向
空闲块中长度小的
初始化 q,使它指向
空闲块中长度大的
按顺序找空闲
输 入申 请内
存大小
输 入申 请内
存大小
p->data.length=requ
est
Y
p 的状态为已分配
N
p->data.length>request
分配不成功
N
Y
剩下
p->data.length-=req
uest
返回到整理分区序号
回收空间的流程图(见下页)
2. 相关数据结构及关键函数说明
使用了 struct free_table 数据结构用来说明分区。包含:分区序号(num)、起始地址
(address)、分区长度(length)和分区状态(state)。
使用了线性表的双向链表存储结构(struct Node),里面包含前驱指针(prior)和后继指
针(next)。一开始定义一条(含有 first 和 end)的链,用开始指针和尾指针开创空间链
表。然后分别按三种算法进行分配和回收。
在该程序中关键函数有,sort()、allocation()、recovery()、和 First_fit()、Best_fit
()、Worst_fit()。其中:
sort()函数用来整理分区序号。如在删序号 3 时,它与前面序号 2 相连在一起了,然
后序号 2 中的长度若满足申请的内存大小,就会在序号 2 中分配,然后序号在 2 的基础
上加 1,一直加,加到与原本序号 3 的下一个序号也就是 4 相等,这时 sort()就开始
有明显的工作了;
allocation()用来分配空间。也是过渡到三个算法中的,当三个算法中满足或者不满足
分配请求,都会又返回值给 allocation();
recovery()用来回收内存。包含四种情况的处理,即释放区上与空闲区邻接、释放区
下与空闲区邻接、释放区上下都与空闲区邻接、释放区上下都与空闲区不邻接。
7