山东大学操作系统实验报告完整版Word格式.docx
《山东大学操作系统实验报告完整版Word格式.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统实验报告完整版Word格式.docx(18页珍藏版)》请在冰豆网上搜索。
![山东大学操作系统实验报告完整版Word格式.docx](https://file1.bdocx.com/fileroot1/2022-11/25/2a3bdc18-d29c-47dd-9de0-9c6bd3e452b1/2a3bdc18-d29c-47dd-9de0-9c6bd3e452b11.gif)
答:
进程是一个可并发执行的程序在某数据集上的一次运行,是程序的一次运行过程。
而程序只是进程的一个组成部分,进程是程序的执行过程。
程序是静态的指令集合,而进程是动态的过程实体,是动态的产生、发展和消失。
此外所谓的进程并发执行是在宏观上并发,而在微观上交替执行。
每个进程都用一个唯一的整数形式的进程标识符来标识,通过fork()系统调用,可创建新进程。
新进程通过复制原来进程的地址空间而成。
这种机制允许父子进程方便的进行通信。
系统调用fork(),得到的子进程实际上是父进程的克隆体,要执行不同的新程序要使用系统调用exec(),以用新程序来取代进程的内存空间。
其功能是根据参数指定的文件名找到程序文件,把它装入内存,覆盖原来进程的映像,形成一个不同于父进程的子进程。
除了进程映像被更换之外,新进程的PID及其他PCB属性均保持不变,实际上是一个新进程“借壳”原来子进程开始运行。
父进程可通过系统调用waitpid()来把自己移出就绪队列来等待子进程的终止。
2.信号的机理是什么怎样利用信号实现进程控制
每个信号对应一个正整数常量(为signal?
number。
定义在系统头文件<
>
中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。
每个进程运行时,要通过信号机制来检查是否有信号到达。
若有,中断正在执行的程序,转向该信号相对应的处理程序,已完成对事件的处理;
处理结束后再返回到原来的断点继续执行。
实验代码
文件:
#include"
"
intmain()
{
intpid_1,pid_2;
.\n"
);
sleep(3);
后再输出各自进程号、优先数和调度策略。
以上行为通过for()语句循环。
新建一个文件夹,在该文件夹中建立以下名为的C语言程序。
再建立以下名为的C语言头文件。
建立项目管理文件Makefile。
输入make命令编译连接生成可执行的pctl程序。
执行并调试pctl程序
进程调度调度策略和功能如下所示:
SCHED_OTHER默认的分时调度策略(值等于0)
SCHED_FIFO先进先先出调度策略(值等于1)
SCHED_RR时间片轮转调度策略(值等于2)
进程调度本质就是让谁先执行,让谁后执行。
在真实的操作系统中,由调度策略和优先级决定谁先执行。
Linux的调度策略有三种,SCHED_OTHER分时调度,SCHED_FIFO先进先出,SCHED_RR时间片轮转。
后两种专用于对响应时间有特殊要求的进程,并且会抢先于SCHED_OTHER调度策略的进程而执行。
通过这个系统调用设置进程调度策略,intsched_setscheduler(pid_tpid,intpolicy,conststructsched_param*sp);
其中pid是进程号,policy是以上说明的3种调度策略之一,sp调度参数结构指针,调度参数结构主要存有调度优先数。
进程优先数(prio)由静态优先级和动态优先级两部分组成。
静态优先级与调度策略有关。
动态优先级由以下系统调用设置,intsetpriority(intwhich,intwho,intprio);
which设置的对象。
可以是:
进程PRIO_PROCESS
进程组PRIO_PGRP
用户PRIO_USER
who对应设置对象的进程号或组号或用户号
prio要设置的进程优先数
#include<
#include<
sys/>
#defineSIGINT2
#defineSIGTSTP20
voidhandler_sigint(intsigno){放顺序要指定。
分别是烟草,纸和胶水。
每一个供应者供应的物品有三种,(烟草+纸)(烟草+胶水)(纸+胶水)。
三个消费者分别需要三个里面的一种。
约束:
(1)某一时刻,只能有一个供应者,放入一对物品。
(2)某一时刻,只能有一个消费者,且要保证这个消费者恰好需要的就是刚刚生产的物品。
(3)所有供应者提供这种物品之后,不论它要生产什么物品,只有等到消费者拿走了物品之后,才能继续生产。
(1)供应者的上下文完全一样,在程序中fork()子进程之后,让父进程和子进程并发执行供应者代码即可。
(2)消费者有三个,且每个消费者需要的物品不同,所以不能使用同一个代码段。
这样,就需要建立两个子进程和一个父进程同时并发执行。
然后在各自区域执行相似的但不同的代码段。
(3)用信号灯实现同步和互斥约束。
(4)创建公共缓冲区和指向首地址的指针
得进程并发执行时保持同步。
因为如果信号灯的值小于0,那么这个进程会阻塞,这就是为什么能够同步。
操作系统中,进程同步可以通过信号量机制实现。
在本实验中,信号灯就是信号量,down()操作就是信号量的wait操作,up()操作就是信号量的signal操作。
#defineBUFSZ256
....\n"
getpid(),buff_ptr[*cget_ptr+1],buff_ptr[*cget_ptr+2]);
getpid(),buff_ptr[*cget_ptr+1],buff_ptr[*cget_ptr]);
getpid(),buff_ptr[*cget_ptr+2],buff_ptr[*cget_ptr]);
例实验程序中模拟两种置换算法:
LRU算法和FIFO算法
2.能对两种算法给定任意序列不同的页面引用串和任意帧实内存块数的组合测试,显示页置换的过程。
3.能统计和报告不同置换算法情况下依次淘汰的页号、缺页次数(页错误数)和缺页率。
比较两种置换算法在给定条件下的优劣。
4.为了能方便的扩充页面置换算法,更好的描述置换过程,示例实验程采用了C++语言用Replace类描述了置换算法及其属性。
请在以上示例实验程序中补充“增强二次机会”等置换算法的模拟程序。
输入不同的内存页面引用串和实存帧数,观察并分析其页面置换效果和性能,并将其与LRU和FIFO算法进行比较。
改进以上示例实验程序,使之能够随机的产生内存页面引用串,以便能动态的观测各种置换算法的性能。
Clock()算法:
FIFO算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:
检查最老页面的R位,如果R位为0,那么这个页面既老又没有被使用过,可以立刻被置换掉,如果R位为1,就将R位清0,并将这个页面重新插入链表尾端,然后继续搜索。
第二次机会算法是寻找一个最近时间间隔内未被访问过的页面,如果所有的页面都被访问过了,这个算法就是纯粹的FIFO算法。
EClock()算法:
需将内存中的页面按访问位A和修改位M分为4类:
第一类(A=0,M=0)未被访问,又未被修改,是最佳替换页
第二类(A=0,M=1)未被访问,但被修改过,次佳替换页
第三类(A=1,M=0)被访问过,但未被修改,可能再被访问
第四类(A=1,M=1)以访问且被修改,可能再被访问
程序首先查找第一类页面,如果有则替换,如果没有则查找第二类页面;
置页面的访问位为0,如果有则替换,如果没有则返回重新查找第一类页面;
如果有则替换,如果没有则查找第二类页面,则一定存在。
该算法适用于某些页面经常被修改的场合。
LFU()算法:
即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。
但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。
MFU算法:
与LFU算法相反,为最经常使用页置换算法。
认为引用次数最小的页以后可能会经常使用。
建立程序,将代码写到程序中;
再建立名为的C语言头文件;
建立以下项目管理文件Makefile;
输入make命令编译连接生成可执行的vmrp程序;
执行程序。
iostream>
cstdlib>
usingnamespacestd;
Replace:
:
Replace()
inti;
例实验程序中模拟两种磁盘移臂调度算法:
SSTF算法和SCAN算法。
2.能对两种算法给定任意序列不同的磁盘请求序列,显示响应磁盘请求的过程。
3.能统计和报告不同算法情况下响应请求的顺序、移臂的总量。
比较两种算法在给定条件下的优劣。
4.为了能方便的扩充磁盘移臂调度算法,更好的描述磁盘移臂调度过程,示例实验程序采用了C++语言用DiskArm类描述了磁盘移臂调度算法及其属性。
请在以上示例实验程序中补充SCAN,C-SCAN,LOOK磁盘移臂调度算法的模拟程序。
输入不同的磁盘柱面请求序列,观察和分析其调度效果和性能,并将其与FCFS和SSTF算法进行比较。
改进以上示例实验程序,使之能够随机的产生磁盘柱面请求序列,以便能动态的观测各种调度算法的性能。
扫描算法(SCAN):
磁臂从磁盘的一端向另一端移动,同时当磁头移过每个柱面时,处理位于该柱面上的服务请求。
当到达另一端时,磁头改变方向,处理继续。
磁头在磁盘上来回扫描。
有时被称为电梯算法。
此算法基本上克服了最短寻道时间优先算法的服务集中于中间磁道和响应时间变化比较大的缺点,而具有最短寻道时间优先算法的优点即吞吐量较大,平均响应时间较小,但由于是摆动式的扫描方法,两侧磁道被访问的频率仍低于中间磁道。
如在本例中,开始时,在53号柱面执行操作的读写磁头的移动臂方向是由里向外,趋向37号柱面的位置,因此,当访问53号柱面的操作结束后,沿臂移动方向最近的柱面是37号柱面。
所以应先为37号柱面的访问者服务,然后是为14号柱面访问者服务。
在柱面0时,磁头会调转方向,朝磁盘的另一端移动,并处理柱面65、67、98、122、124、183.
循环扫描算法(CSCAN):
循环扫描算法是对扫描算法的改进。
如果对磁道的访问请求是均匀分布的,当磁头到达磁盘的一端,并反向运动时落在磁头之后的访问请求相对较少。
这是由于这些磁道刚被处理,而磁盘另一端的请求密度相当高,且这些访问请求等待的时间较长,为了解决这种情况,循环扫描算法规定磁头单向移动。
例如,只自里向外移动,当磁头移到最外的被访问磁道时,磁头立即返回到最里的欲访磁道,即将最小磁道号紧接着最大磁道号构成循环,进行扫描。
由于本例中已假定读写的当前位置在53号柱面,从53号柱面继续向外扫描,依次为37、14、0各柱面的访问者服务,此时移动臂已经是最外的柱面,于是立即返回到199号柱面,重新扫描,依次为183、124、122、98、67、65号柱面的访问者服务。
LOOK算法:
LOOK算法是SCAN算法的一种改进。
对LOOK算法而言磁头同样在最内圈和最外圈磁道之间往返移动。
但LOOK算法发现所移动的方向不再有请求时立即改变移动方向而SCAN算法则需移动到最外圈或最内圈时才改变移动方向。
在新建文件夹中建立以下文件;
在新建文件夹中建立以下Makefile文件;
执行make命令编译连接,生成可执行文件dask;
执行dask命令,输入当前道号,当前寻道方向,当前请求寻道数,当前请求寻
道的道号串。
SCAN和C-SCAN对于磁盘负荷较大的系统会执行的更好,这是因为它不可能产生饿死问题。
SCAN算法基本上克服了最短寻道时间优先算法的服务集中于中间磁道和响应时间变化比较大的缺点,而具有最短寻道时间优先算法的优点即吞吐量较大,平均响应时间较小,但由于是摆动式的扫描方法,两侧磁道被访问的频率仍低于中间磁道。
文件:
DiskArm:
DiskArm(){
//输入当前道号
cout<
<
"
PleaseinputCurrentcylinder:
;
cin>
CurrentCylinder;
//磁头方向,输入0表示向小道号移动,1表示向大道号移动
PleaseinputCurrentDirection(0/1):
SeekDirection;
//输入磁盘请求数,请求道号
PleaseinputRequestNumbers:
RequestNumber;
PleaseinputRequestcylinderstring:
;
Request=newint[sizeof(int)*RequestNumber];
Cylinder=newint[sizeof(int)*RequestNumber];
for(i=0;
i<
i++)
Request[i];
}
~DiskArm(){
//初始化道号,寻道记录
voidDiskArm:
InitSpace(char*MethodName)
endl<
MethodName<
endl;
SeekNumber=0;
SeekChang=0;
Cylinder[i]=Request[i];
//统计报告算法执行情况
Report(void){
SeekNumber:
<
SeekNumber<
ChangDirection:
SeekChang<
//先来先服务算法
Fcfs(void)
intCurrent=CurrentCylinder;
intDirection=SeekDirection;
InitSpace("
FCFS"
Current;
for(inti=0;
i<
RequestNumber;
i++){
if(((Cylinder[i]>
=Current)&
&
!
Direction)||((Cylinder[i]<
Current)&
Direction)){
//需要调头
SeekChang++;
//调头数加1
Direction=!
Direction;
//改变方向标志
//报告当前响应的道号
Current<
->
Cylinder[i];
}
else//不需调头,报告当前响应的道号
Cylinder[i];
//累计寻道数,响应过的道号变为当前道号
SeekNumber+=abs(Current-Cylinder[i]);
Current=Cylinder[i];
//报告磁盘移臂调度的情况
Report();
Sstf(void)
intShortest;
intDistance=999999;
SSTF"
//查找当前最近道号
for(intj=0;
j<
j++){
if(Cylinder[j]==-1)continue;
//-1表示已经响应过了
if(Distance>
abs(Current-Cylinder[j])){
//到下一道号比当前距离近,下一道号为当前距离
Distance=abs(Current-Cylinder[j]);
Shortest=j;
}
if(((Cylinder[Shortest]>
Direction)||((Cylinder[Shortest]<
CurrentCylinder)&
Cylinder[Shortest];
Cylinder[Shortest];
SeekNumber+=abs(Current-Cylinder[Shortest]);
Current=Cylinder[Shortest];
//恢复最近距离,销去响应过的道号
Distance=999999;
Cylinder[Shortest]=-1;
//电梯调度算法
Scan(void){
SCAN"
//打印出当前道号
intindex=-1;
intDistance=999999;
j<
j++){
if(Cylinder[j]==-1)
continue;
elseif((Direction==0&
Cylinder[j]<
Current&
(Current-Cylinder[j])<
Distance)
||(Direction==1&
Cylinder[j]>
(Cylinder[j]-Current)<
Distance)){
index=j;
Distance=abs(Current-Cylinder[j]);
if(Direction==0){
if(index!
=-1){
cout<
->
Cylinder[index];
SeekNumber+=Current-Cylinder[index];
Current=Cylinder[index];
Cylinder[index]=-1;
}else{
0<
endl;
SeekNumber+=Current;
Direction=!
Direction;
//cout<
0;
Current=0;
i--;
elseif(Direction==1){
SeekNumber+=Cylinder[index]-Current;
199<
SeekNumber+=199-Current;
199;
Current=199;
//报告磁盘移臂调度的情况
Report();
//LOOK调度算法
Look(void){
Look"
intDis