《计算机操作系统》实验指导书.docx
《《计算机操作系统》实验指导书.docx》由会员分享,可在线阅读,更多相关《《计算机操作系统》实验指导书.docx(29页珍藏版)》请在冰豆网上搜索。
《计算机操作系统》实验指导书
《计算机操作系统》
实验指导书
(适合于计算机科学与技术专业)
湖南工业大学计算机与通信学院
二O一三年十月
前言
计算机操作系统是计算机科学与技术专业的主要专业基础课程,其实践性、应用性很强。
实践教学环节是必不可少的一个重要环节。
计算机操作系统的实验目的是加深对理论教学内容的理解和掌握,使学生较系统地掌握操作系统的基本原理,加深对操作系统基本方法的理解,加深对课堂知识的理解,为学生综合运用所学知识,在Linux环境下调用一些常用的函数编写功能较简单的程序来实现操作系统的基本方法、并在实践应用方面打下一定基础。
要求学生在实验指导教师的帮助下自行完成各个操作环节,并能实现且达到举一反三的目的,完成一个实验解决一类问题。
要求学生能够全面、深入理解和熟练掌握所学内容,并能够用其分析、设计和解答类似问题;对此能够较好地理解和掌握,并且能够进行简单分析和判断;能够熟练使用Linux用户界面;掌握操作系统中进程的概念和控制方法;了解进程的并发,进程之间的通信方式,了解虚拟存储管理的基本思想。
同时培养学生进行分析问题、解决问题的能力;培养学生完成实验分析、实验方法、实验操作与测试、实验过程的观察、理解和归纳能力。
为了收到良好的实验效果,编写了这本实验指导书。
在指导书中,每一个实验均按照该课程实验大纲的要求编写,力求紧扣理论知识点、突出设计方法、明确设计思路,通过多种形式完成实验任务,最终引导学生有目的、有方向地完成实验任务,得出实验结果。
任课教师在实验前对实验任务进行一定的分析和讲解,要求学生按照每一个实验的具体要求提前完成准备工作,如:
查找资料、设计程序、完成程序、写出预习报告等,做到有准备地上机。
进行实验时,指导教师应检查学生的预习情况,并对调试过程给予积极指导。
实验完毕后,学生应根据实验数据及结果,完成实验报告,由学习委员统一收齐后交指导教师审阅评定。
实验成绩考核:
实验成绩占计算机操作系统课程总评成绩的20%。
指导教师每次实验对学生进行出勤考核,对实验效果作记录,并及时批改实验报告,综合评定每一次的实验成绩,在学期终了以平均成绩作为该生的实验成绩。
有以下情形之一者,实验成绩为不及格:
1.迟到、早退、无故缺勤总共3次及以上者;
2.未按时完成实验达3次及以上者;
3.缺交实验报告2次及以上者。
目录
第一部分实验环境及所用系统函数介绍1
1.1Linux操作系统简介1
1.2Linux的使用1
1.2.1vi的使用1
1.2.2gcc的使用2
1.2.3主要系统调用函数2
第二部分实验内容5
实验一熟悉LINUX基本命令及编程环境5
实验二进程管理8
实验三进程调度12
实验四进程间通信17
实验五存储管理实验20
第一部分实验环境及所用系统函数介绍
DOS操作系统是单道操作系统,无法进行多道程序设计,Windows环境下的VisualC++虽然也可用于多道程序设计,但是并不是完全的多道,因为它也可用于DOS编程。
所以我们的实验选用Linux操作系统。
Linux操作系统是一个类UINX操作系统,是一个纯多道并发的网络操作系统。
1.1Linux操作系统简介
Linux是一个多用户操作系统,是UNIX的一个克隆版本(界面相同但内部实现不同),同时它是一个自由软件,是免费的、源代码开放的,这是它与UNIX的不同之处。
现在,Linux凭借优秀的设计,不凡的性能,加上IBM、Intel、CA、CORE、Oracle等国际知名企业的大力支持,市场份额逐步扩大,已成为与Windows和UNIX并存的三大主流操作系统之一。
1.2Linux的使用
1.2.1vi的使用
1)vi的简单应用
vi是linux环境下赫赫有名的文本编辑工具之一。
进入vi编辑器的方法:
vifilename.c注:
文件名必须带有扩展名.c,如filename.c否则无法通过编译;
进入vi后要按:
按“i”键从命令方式切换到输入方式;
从输入方式切换到命令方式的方法:
按“Esc”键
保存文件:
w
保存文件并退出:
wq
不保存文件退出:
q!
注:
以上操作必须在命令方式下进行。
2)其他常用vi操作命令
j,k,h,l:
上下左右
0:
行首
$:
行尾
ctrl+f :
后翻页
ctrl+b:
前翻页
G :
文件尾
数字G:
数字所指定行
i,I :
插入命令,i 在当前光标处插入, I 行首插入
a,A:
追加命令,a 在当前光标后追加,A 在行末追加
o,O:
打开命令,o 在当前行下打开一行,O在当前行上插入一行
x:
删除光标处字符
dd:
删除当前行
d0:
删除光标前半行
d$:
删除光标后半行
r,R :
替换命令,r 替换当前光标处字符,R从光标处开始替换
/string:
查找字符串
n:
继续查找
N:
反向继续查找
% :
查找对应括号
u :
取消上次操作
注:
以上操作必须在命令方式下进行。
1.2.2gcc的使用
gcc是linux下的一种c程序编译工具,使用方法如下(有提示符#的情况):
编译:
gcc–ofilename1filename.c
其中:
filename.c是源文件名,filename1是目标文件名,o代表object
执行:
./filenamel
示例:
键入一简单的程序:
viab.c按回车键输入以下代码段,
#include
#include
main()
{printf(“aaaa”);
}
按ESC键,再按“:
WQ”(W是保存,Q是退出)
出现提示符:
[root@GGG-LINUXroot]#
键入:
gcc–oabab.c进行编译。
执行:
./ab
1.2.3主要系统调用函数
1.2.1系统调用fork()
功能:
创建一个新的进程.
头文件:
#include
说明:
本系统调用产生一个新的进程,叫子进程,是调用进程的一个复制品.调用进程叫父进程,子进程继承了父进程的几乎所有的属性。
(1)该子进程继承了父进程的程序空间,复制了父进程的数据段和栈段。
也就是说不管是父进程还是子进程,在占有处理机后,都从fork()调用的返回点开始运行;
(2)调用成功则对父进程返回子进程标识号pid;
(3)调用成功对子进程返回0,这也是最方便的区分父子进程的方法。
(4)若调用失败则返回-1给父进程,子进程不生成。
注意:
如果fork()值>0,>0的数即是子进程号。
但这时是父进程占有处理机。
1.2.2系统调用wait(&status):
功能:
等待子进程结束。
(1)当有多个子进程时,任一个子进程结束即将控制返回调用者,并将子进程调用exit(status)时的status值送到&status指针所指单元中。
(2)在控制返回调用者时,同时将所等到的子进程pid作为wait()系统调用函数的返回值。
(3)waitpid(pid,…):
等待pid所指定的进程结束。
(4)返回值:
等待到一个子进程返回时,返回值为该子进程号;否则返回值为–1。
说明:
允许调用进程(即父进程)取得子进程的状态信息,调用进程将会挂起直到其一个子进程终止。
1.2.3系统调用exit()
功能:
终止进程.
语法:
#include
voidexit(status)
intstatus
功能:
调用进程被该系统调用终止。
该系统调用发出后,操作系统将从系统中删除调用exit的进程,并将status值传给等待它结束的父进程。
返回值:
无
1.2.4系统调用kill()
功能:
向一个或一组进程发送一个信号。
语法:
#include
intkill(pid,sig);
pid_tpid;intsig;
说明:
向一个或一组进程发送一个信号,该信号由参数sig指定,为系统给出的信号表中的一个。
Sig是signal的缩写。
返回值:
调用成功则返回0,否则返回-1.
kill-STOP[pid]:
发送SIGSTOP(17,19,23)停止一个进程,而并不消灭这个进程。
kill-CONT[pid]:
发送SIGCONT(19,18,25)重新开始一个停止的进程。
kill-KILL[pid]:
发送SIGKILL(9)强迫进程立即停止,并且不实施清理操作。
kill-9-1:
终止拥有的全部进程。
SIGKILL和SIGSTOP信号不能被捕捉、封锁或者忽略。
1.2.5系统调用lockf()
功能:
应用、检测或删除打开文件的一个POSIX锁
语法:
#include
intlockf(intfd,intcmd,off_tlen);
说明:
应用、检测或删除打开文件某部分的一个POSIX锁,文件通过fd指明,文件的描述符的请求操作通过cmd指明。
#defineF_ULOCK0解锁一个区域
#defineF_LOCK1上锁一个区域
#defineF_TLOCK2检测并上锁一个区域
#defineF_TEST3检测一个区域是否上锁
文件上锁区域的请求起始于隐含的偏移并包好len字节,假如len为负,从pos…pos+len-1,这里pos为当前文件位置,假如len为零,则位置从当前文件位置延伸延伸到无限长,包括当前和以后的文件最后的位置。
在所有情况下,位置可延伸到以前当前的文件的最后位置。
在Linux中,这称为fcntl
(2)的接口(一般会指明lockf和fcntl的关系)。
1.2.6系统调用pipe()
是用来建立管道的。
语法:
#include
intpipe(intfd[2]);这里fd[1]为写入端,fd[0]为读出端。
功能:
从管道里写或从管道里读。
第二部分实验内容
实验一熟悉LINUX基本命令及编程环境
1、实验类型
本实验为验证性实验。
2、实验目的与任务
1)熟悉使用Linux字符界面,窗口系统的常用命令;
2)熟悉运用Linux常用的编程工具;
3)熟悉运用Linux的在线求助系统。
3、预习要求
1)熟悉一种操作系统的使用和安装,如windows操作系统的安装,DOS系统的使用
2)了解进程的概念及进程的状态
3)熟悉c语言程序设计
4)熟悉c语言程序编译过程
4、实验基本原理
进入Linux操作系统后,控制终端的命令行输入方式下输入各种命令,并显示各种命令操作后的输出结果,操作包括文件操作命令的使用,vi命令的使用以及gcc编译器的使用,详细的各种命令及使用方式见第一部分的介绍。
5、实验仪器与设备(或工具软件)
实验设备:
计算机一台,软件环境要求:
安装RedHatLinux操作系统和gcc编译器。
6、实验内容
1)使用常用的操作命令ls,cp,rm,mkdir,man,vi等。
2)熟悉怎么编辑一个程序(编辑,调试,运行见),输入一个简单的C程序进行练习,参考练习程序如下:
程序1
#include
main()
{
intp1;
while((p1=fork())==-1);
if(p1==0)
putchar(‘B’);
elseputchar(‘A’);
}
}
程序2
#include
#include"stdafx.h"
main()
{
introw,column,num,n=6;
for(row=1;row{for(column=1;columnprintf("");
for(num=row;num>=1;num--)
printf("%d",num);
for(num=2;num<=row;num++)
printf("%d",num);
printf("\n");
}}
7、实验步骤
1)进入Linux操作系统
开机后,选择进入Linux操作系统方式,输入用户名和密码,即可进入Linux操作系统。
2)进入控制终端的命令行输入方式
在Linux操作系统环境下,点击“小红帽”菜单,选择“系统”下拉菜单,选择“终端”选项,进入命令行输入方式。
3)输入命令后按回车键
在命令行输入方式下,输入各种文件操作命令,并按回车查看显示结果。
8、注意事项
1)gcc编译器不能编译不带扩展名的c语言程序。
2)注意编译和运行程序的基本过程。
3)注意熟练使用man命令来查看某条命令的含义及使用方式。
9、实验报告要求
要求列出多条命令的使用和相应结果,需要列出运行了的程序清单及相应结果,并对结果进行分析和讨论。
实验二进程管理
1、实验类型
本实验为设计性实验。
2、实验目的与任务
1)加深对进程概念的理解,明确进程和程序的区别。
2)进一步认识并发执行的实质
3、预习要求
1)进程的概念
2)进程控制的概念及内容
3)进程的并发执行
4)熟悉互斥的概念
5)用到的Linux函数有:
fork(),lockf()等。
4、实验基本原理
使用fork()系统调用来创建一个子进程,父进程和子进程并发执行,交替输出结果。
使用lockf()系统调用对临界区进行加锁操作,实现对共享资源的互斥使用。
5、实验仪器与设备(或工具软件)
实验设备:
计算机一台,软件环境要求:
安装RedHatLinux操作系统和gcc编译器。
6、实验内容
1)进程的创建
编写一段程序,使用系统调用fork()创建两个子程序。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:
父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。
运行程序10次,观察记录屏幕上的显示结果,并分析原因。
2)进程的控制
修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。
如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程间的互斥,观察并分析出现的现象。
(1)进程的创建参考程序如下:
#include
main()
{
intp1,p2;
while((p1=fork())==-1);
if(p1!
=0)
{
while(((p2=fork())==-1);
if(p2==0)putchar('b');
elseputchar('c');
}
elseputchar('a');
}
运行结果:
bca(或bac)
分析:
从进程并发执行来看,输出bac,acb等情况都有可能。
原因:
fork()创建进程所需的时间要多于输出一个字符的时间,因此在主程序创建进程的同时,进程2就输出了”b”,而进程2和主程序的输出次序是随机的,所以出现上述结果。
(2)进程的控制参考程序如下
#include
main()
{intp1,p2,i;
while((p1=fork())==-1);
if(p1==0)
{for(i=0;i<500;i++)
printf("child%d\n",i);
}
else
{
while((p2=fork())==-1);
if(p2==0)
for(i=0;i<500;i++)
printf("son%d\n",i);
elsefor(i=0;i<500;i++)
printf("daughter%d\n",i);
}
}
运行结果:
略
分析:
由于函数printf()输出和字符串之间不会被中断,因此字符串内部的字符顺序输出不变。
但是由于进程并发执行时的调度顺序和父进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。
进程加锁后的参考程序如下:
#include
main()
{intp1,p2,i;
while((p1=fork())==-1);
if(p1==0)
{
lock(1,1,0);
for(i=0;i<500;i++)
printf("child%d\n",i);
lock(1,0,0);
}
else
{
while((p2=fork())==-1);
if(p2==0)
{
lock(1,1,0)
for(i=0;i<500;i++)
printf("son%d\n",i);
lock(1,0,0)
else
{
lock(1,1,0)
for(i=0;i<500;i++)
printf("daughter%d\n",i);
lock(1,0,0)
}
}
}
运行结果:
略
分析:
学生自己完成
7、实验步骤
1)进入vi编辑器
2)在编译器中输入所要运行的程序代码
3)退出编辑器,返回命令行输入方式,使用gcc编译器编译程序,获得能运行的目标程序。
4)运行目标程序,查看运行结果。
8、注意事项
1)如果使用gcc编译程序有错的话,需要重新修改程序,直到无错为止。
2)注意系统是如何创建进程的?
3)查看结果是否是交替输出,如果修改输出的次数是否会出现交替现象?
4)相关函数的介绍见第一部分的介绍。
9、实验报告要求
需要列出运行了的程序清单及相应结果,并对结果进行分析和讨论。
对结果的分析主要讨论结果为什么会交替出现?
并发进程是如何执行的?
实验三进程调度
1、实验类型
本实验为综合性实验
2、实验目的与任务
在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。
当就绪进程个数大于处理机数时,就必须依照某种策略来决定那些进程优先占用处理机。
本实验模拟在单处理机情况下的处理机调度,帮助学生加深了解处理机调度的工作。
3、预习要求
1)熟悉进程控制块和进程组织方式
2)熟悉进程调度的概念
3)熟悉时间片轮转调度算法等
4)熟悉c语言编程,指针及结构体等知识
5)数据结构中的链表的建立及基本操作
4、实验基本原理
进程控制块通过链表队列的方式组织起来,系统中存在运行队列和就绪队列(为简单起见,不设阻塞队列),进程的调度就是进程控制块在运行队列和就绪队列之间的切换。
当需要调度时,从就绪队列中挑选一个进程占用处理机,即从就绪队列中删除一个进程,插入到运行队列中,当占用处理机的进程运行的时间片完成后,放弃处理机,即在运行队列中的进程控制块等待一段时间(时间片)后,从该队列上删除,如果该进程运行完毕,则删除该进程(节点);否则,则插入到就绪队列中。
5、实验仪器与设备(或工具软件)
实验设备:
计算机一台,软件环境要求:
安装RedHatLinux操作系统和gcc编译器。
6、实验内容
设计一个时间片轮转调度算法实现处理机调度的程序,具体内容如下
1)实验中使用的数据结构
(1)PCB进程控制块
内容包括参数①进程名name;②要求运行时间runtime;③优先数prior;④状态state;⑤已运行时间runedtime。
(2)为简单起见,只设运行队列,就绪链表两种数据结构,进程的调度在这两个队列中切换,如图3.1所示
图3.1PCB链表
2)每个进程运行时间随机产生,为1~20之间的整数。
3)时间片的大小由实验者自己定义,可为3或5
4)可参考的程序流程图如图3.2
图3.2模拟进程调度的流程图
5)参考程序
#include"stdio.h"
#include"stdlib.h"
typedefstructPCB
{
intname;
intruntime;
intrunedtime;
intstate;
intkilltime;
structPCB*next;
}PCB;
#defineNUM10
voidmain()
{
inttimeslice=3;
PCB*runqueue;
PCB*top,*tail,*temp;
inti;
srand(10);
for(i=0;i{
temp=newPCB;
temp->name=i;
temp->runtime=rand()%20;
temp->runedtime=0;
temp->next=NULL;
temp->killtime=0;
if(i==0){top=temp;tail=temp;}
else{
tail->next=temp;
tail=temp;
}
printf("processname%d,runtime=%d,runedtime=%d,killtime=%d\n"
tail->name,tail->runtime,tail->runedtime,tail->killtime);
}
while(top!
=NULL)
{
runqueue=top;
top=top->next;
runqueue->next=NULL;
runqueue->runtime=runqueue->runtime-timeslice;
if(runqueue->runtime<=0)
{
runqueue->killtime=runqueue->runtime+timeslice;
runqueue->runedtime=runqueue->runedtime+runqueue->killtime;
runqueue->runtime=0;
printf("processname%d,runtime=%d,runedtime=%d,killtime=%d\n"
runqueue->name,runqueue->runtime,runqueue->runedtime,runqueue->killtime);
}
else{
runqueue->killtime=timeslice;
runqueue->runedtime=runqueue->runedtime+runqueue->killtime;
printf("processname%d,runtime=%d,runedtime=%d,killtime=%d\n"
runqueue->name,runqueue->runtime,runqueue->runedtime,runqueue->killtime);
tail->next=runqueue;
tail=tail->next;
}
}
}
6)运行结果,包括各个进程的运行顺序,每次占用处理机的运行时间,可以参考下列输出如图4.3。
图4