《操作系统》实验手册.docx
《《操作系统》实验手册.docx》由会员分享,可在线阅读,更多相关《《操作系统》实验手册.docx(16页珍藏版)》请在冰点文库上搜索。
《操作系统》实验手册
《操作系统》实验手册
第一部分系统调用函数说明、参数值及定义
✧fork()
创建一个进程,其格式为:
Intfork()
其中返回的int取值意义如下:
0:
创建子进程,从子进程返回的id值
大于从父进程返回的子进程id值
-1:
创建失败
✧lockf(files,function,size)
用作锁定文件的某些段或者整个文件,本函数适用头文件为:
#include
参数定义:
intlockf(files,function,size)
intfiles,function:
longsize:
其中:
files是文件描述符:
function是锁定和解锁;1表示锁定,0表示解锁.Size是锁定或解锁的字节数,若用0,表示从文件的当前位置到文件尾.
✧msgget(key,flag):
获得一个消息的描述符,该描述符指定一外消息队列以便用于其他系统调用.
该函数使用头文件如下:
#include
#include
#include
参数定义
intmsgget(key,flag)
key_tkey;
intflag;
语法格式:
msgqid=msgget(key,flag)
其中:
msgqid是该系统调用返回的描述符,失败返回-1;
flag本身由操作允许权和控制命令值相”或”得到.
如:
IPC_CREAT|0400是否该队列应被创建;
IPC_EXCL|0400是否该队列的创建映是互斥的;等。
✧Msgsnd(id,msgp,size,flag):
发送一消息。
该函数使用头文件如下:
#include
#include
#include
参数定义:
intmsgsnd(id,msgp,size,flag)
intid,size,flag;
structmsgbuf*msgp;
其中:
id是返回消息的描述符;msgp是指向用户存储区的一个构造体指针,size指晃由msgp指向的数据结构中字符数组的长度;即消息的长度。
这个数组的最在值由MSG_MAX系统可调用参数来确定。
Flag规定当核心用尽内部缓冲空间时应执行的动作;若在标志flag中未设置IP_NOWAIT位,则当该消息队列中的字节数超过一最大值时,或系统范围的消息超过某一最大值时,调用msgsnd进程睡眠。
若是设置IPC_NOWAIT,则在次情况下,msgsnd立即返回。
✧Msgrcv(id,msgp,size,type,flag):
接受一消息。
该函数调用使用头文件如下:
#include
#include
#include
参数定义:
intmsgrcv(id,msgp,size,flag)
intid,size,type,flag;
structmsgbuf*msgq;
structmsgbuf{longmtype;chatmtext[];};
语法格式:
count=msgrcv(id,msgp,size,type,flsg)
其中:
id是消息描述符,msgp是用来存放欲接收消息的拥护数据结构的地址;size是msgp中数据数级的大小;type是用户要读的消息类型:
type为0:
接收该队列的第一个消息;
type为正:
接收类型type的第一个消息;
type为负:
接收小于或等于type绝对值的最低类型的第一个消息。
Flag规定倘若该队列无消息,核心应当做什么事,如果此时设置了IPC-NOWAIT标志,则立即返回,若在flag中设置了MSG_noerror,且所接收的消息大小大于sixe,核心载断所接受的消息。
Count是返回消息正文的字节数。
✧Msgctl(id,cmd,buf):
查询一个消息描述符的状态,设置它的状态及删除一个消息描述符。
调用该函数使用头文件如下:
#include
#include
#include
参数定义:
intmsgctl(id,cmd,buf)
intid,cmd;
structmsqid_ds*buf;
其中:
函数调用成功时返回0,调用不成功时返回-1。
Id用来识别该消息的描述符;cmd规定命令的类型。
IPC_STAT将与id相关的消息队列首标读入buf。
IPC_SET为这个消息序列设置有效的用户和小组标识及操作允许权和字节的数量。
IPC_RMID删除id的消息队列。
Buf是含有控制参数或查询结果的用户数据结构的地址。
附:
msgid_ds结构定义如下:
structmsgid_ds
{structicp_permmsg_perm;/*许可权结构*/
shortpad1[7];/*由系统使用*/
ushortonsg_qnum;/*队列上消息数*/
ushortonsg_qbytes;/*队列上最大字节数*/
ushortonsg_lspid;/*最后发送消息的PID*/
ushortonsg_lrpid;/*最后接收消息的PID*/
time_tmsg_stime;/*最后发送消息的时间*/
time_tmsg_rtime;/*最后接收消息的时间*/
time_tmsg_ctime;/*最后更改时间*/
};
structipc_perm
{ushortuid;/*当前用户id*/
ushortgid;/*当前进程组id*/
ushortcuid;/*创建用户id*/
ushortcgid;/*创建进程组id*/
ushortmode;/*存取许可权*/
{shorpad1;longpad2}/*由系统使用*/
};
✧Shmget(key,size,flag);
获得一个共享存储区。
该函数使用头文件如下:
#include
#include
#include
语法格式:
shmid=shmget(key,size,flag)
参数定义:
intshmget(key,size,flag)
key_tkey;
intsize,flag;
其中:
size是存储区的字节数,key和flag与系统调用msgget中的参数含义相同。
附:
操作允许权八进制数
用户可读00400
用户可写00200
小组可读00040
小组可写00020
其他可读00004
其他可写00002
控制命令值
IPC_CREAT0001000
IPC_EXCL0002000
如:
shmid=shmget(key,size,(IPC_CREAT|0400));
创建一个关键字为key,长度为size的共享存储区。
✧Shmat(id,addr,flag):
从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。
该函数调用使用头文件如下:
#include
#include
#include
参数定义:
char*shmat(id,addr,flag)
intid,flag;
char*addr;
语法格式:
virtaddr=shmat(id,addr,flag)
其中:
id是共享存储区的标识符,addr是用户要使用共享存储区附接的虚地址,若addr是0,系统选择一个适当的地址来附接该共享区。
Flag规定对此区的读写权限,以及系统是否应对用户规定的地址做舍入操作。
如果flag中设置了shm_rnd即表示操作系统在必要时舍去这个地址。
如果设置了shm_rdonly,即表示只允许读操作。
Viraddr是附接的虚地址。
✧Shmdr(addr):
把一个共享存储区从指定进程的虚地址空间断开。
调用该函数使用头文件:
#include
#include
#include
参数定义:
intshmadt(addr)
char*addr
其中,当调用成功时,返回0值,调用不成功,返回-1,addr是系统调用shmat所返回的地址。
✧Shmctl(id,cmd,buf)
对与共享存储区关联的各种参数进行操作,从而对共享存储区进行控制。
调用该函数使用头文件:
#include
#include
#include
参数定义:
intshmctl(id,cmd,buf)
intid,cmd;
strctshmid-ds*buf;
其中:
调用成功时返回0,否则返回-1。
Id为被共享存储区的标识符。
cmd规定操作的类型。
规定如下:
IPC-STAT:
返回包含在指定shmid相关数据结构中的状态信息,并且把它放置在用户存储区中的*but指针所指的数据结构中。
执行此命令的进程必须有读取允许权。
IPC-SET:
对于指定的shmid,为它设置有效用户和小组标识和操作存储权。
IPC-RMID:
删除指定的shmid以及与它相关的共享存储区的数据结构。
SHM-LOCK:
在内存中锁定指定的共享存储区,必须是超级用户才可以此项操作。
Buf是一用户超级数据结构地址。
附:
shmid-ds
{structipc-permshm-perm;/*许可权结构;*/
intshm-segsz;/*段大小;*/
intpadl;/*由系统使用;*/
ushortshm-lpid;/*最后操作的进程id;*/
ushortshm_cpid;/*创建者的进程id;*/
ushortshm_nattch;/*当前附界数;*/
shortpad2;/*由系统使用;*/
time_tshm_atime;/*最后附接时间;*/
time_tshm_dtime;/*最后断接时间;*/
time_tshm_ctime;/*最后修改时间;*/
}
✧Signal(sig,function):
允许调用进程控制软中断信号处理。
头文件为:
#include
参数定义:
signal(sig,function)
intsig;
void(*func)();
其中:
sig的值是:
SIGHVP挂起
SIGINT键盘按delete键或break键
SIGQUIT键盘按quit键
SIGILL非法指令
SIGIOTIOT指令
SIGEMTEMT指令
SIGFPE浮点运算溢出
SIGKILL要求终止进程
SIGBUS总红错
SIGSEGV段违例
SIGSYS系统调用参数错
SIGPIPE向无读者管道上写
SIGALRM闹钟
SIGTERM软件终结
SIGUSRI用户定义信号
SIGUSR2第二个用户定义信号
SIGCLD子进程死
SIGPWR电源故障
Function的解释如下:
SIG_DEL:
缺省操作。
对除SIGPWR和SIGCLD外所有信号的缺省操作是进程终结对信号SIGQUIT,SIGILL,SIGTRAP,SIGIOT,SIGEMT,SIGFPE,SIGBUS,SIGSEGV和SIGSYS它产生一内存映像文件。
SIG_IGN:
忽视该信号的出现。
Funtion:
在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号SIGILL,SIGTRAP和SIGPWR以外的信号,核心自动地重新设置软中断信号处理程序的值为SIG_DFL,一个进程不能捕获SIGKILL信号。
第二部分实验
实验1系统调用
实验目的
理解系统调用的概念和方法;了解Linux环境;熟悉Linux系统中C的开发工具;
实验预备内容:
(1)上机启动Linux熟悉各种应用软件的使用。
(2)启动程序,熟悉其基本操作。
实验内容:
编写一段程序,使用系统调用open()、creat()、write()和close(),完成文件合并的功能。
实验2进程控制
实验目的
加深对进程概念的理解,明确进程和程序的区别;进一步认识并发执行的实质;分析进程争用资源的现象,学习解决进程互斥的方法;了解linux系统中进程通信的基本原理。
实验预备内容:
(1)阅读linux的sched.h源码文件,加深对进程管理概念的理解。
(2)阅读linux的fork.c源码文件,分析进程的创建过程。
实验内容:
(1)进程的创建
编写一段程序,使用系统调用fork()创建两个子进程。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:
父进程显示字符“a”;子进程分别显示字符“b“和字符“c”。
试观察记录屏幕上的显示结果,并分析原因。
(2)进程的控制
修改已编写的程序,将每个进程输出一个字符改为每个进程输出一句话,在观察程序执行时屏幕上出现的现象,并分析原因。
如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
(3)①编制一段程序,使其实现进程的软中断通信。
要求:
使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL键);当捕捉到中为信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输入下列信息后终止:
childprocesslliskilledbyparent!
Childprocess12iskilledbyparent!
父进程等待两个子进程终止后,输出如下的信息后终止:
parentprocessiskilled!
②在上面的程序中增加语句signal(SIGINT,SIG_IGN)和signal(SIGQUIT,SIG_IGN),观察执行结果,并分析原因。
(4)进程的管道通信
编制一段程序,实现进程的管道通信。
使用系统调用pipe()建立一条管道线;两个进程p1和p2分别向管道各写一句话:
child1issendingamessage!
child2issendingamessage!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。
要求父进程先接收子进程p1发来的消息,然后再接收子进程p2发来的消息。
思考:
系统是怎样创建流程的?
可执行文件加载时进行了哪些处理?
当首次调用新创建进程时,其入口在哪里?
进程通信有什么特点?
实验3进程间通信(2011-2012免做)
实验目的:
linux系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据。
本实验的目的是了解和熟悉linux支持的消息通信机制,共享存储区机制及信息量机制。
实验预备内容:
阅读linux系统的msg.c、sem.c和shm.c等源码文件,熟悉linux的三种通信机制。
实验内容:
(1)消息的创建,发送和接收。
使用系统调用msgget(),msgsnd(),msgrev()及msgctl()编制一长度为1K的消息的发送和接收程序。
观察上面程序,说明控制消息队列系统调用msgctl()在此起什么作用?
(2)共享存储区的创建、附接和断接。
使用系统调用shmget(),shmat(),sgmdt(),shmctl(),编制一个与上述功能相同的程序。
(3)比较上述
(1),
(2)两种消息通信机制中数据传输的时间。
实验4进程管理(生产者-消费者)
一、实验目的:
通过对“生产者-消费者”问题编程实现,了解线程创建、同步信号量、互斥信号量、临界区的创建和使用。
了解线程互斥和同步机制。
了解PV原语和信号量在线程互斥和同步机制中的运用。
二、实验内容
有界缓冲区内设有5个存储单位,放入/取出的数据项设定为1~5这5个整形数。
要求每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前生产者/消费者标识符
三、设计分析和主要设计结构
实验陈述:
1、基础知识:
本实验用到几个API函数:
CreatThread,CreatMutex,CreatSemaphore,WaitForSingleObject,ReleaseSemaphore,ReleaseMutex,InitializeCriticalSection,EnterCriticalSection,LeaveCriticalSection
这些函数的作用:
CreatThread:
创建一个线程,该线程在调用进程的地址空间中执
CreatMutex:
产生一个命名的或者匿名的互斥量对象。
WaitForSingleObject(对应p操作)锁上互斥锁,ReleaseMutex(对应v操作)打开互斥锁。
CreateSemaphore:
创建一个命名的或者匿名的信号对象。
信号量可以看作是在互斥量上的一个扩展。
WaitForSingleObject:
使程序处于等待状态,直到信号量(或互斥量)hHandle出现或者超过规定的等待最长时间,信号量出现指信号量大于或等于1,互斥量出现指打开互斥锁。
在返回之前将信号量减1或者锁上互斥锁。
ReleaseSemaphore:
将所指信号量加上指定大小的一个量,执行成功,则返回非0值。
ReleaseMutex:
用来打开互斥量,即将互斥量加1。
成功调用则返回0。
InitializeCriticalSection:
该函数初始化临界区对象。
EnterCriticalSection:
该函数用于等待指定临界区对象的所有权。
当调用线程被赋予所有权时,该函数返回。
LeaveCriticalSection:
该函数释放指定的临界区对象的所有权。
实验5死锁避免—银行家算法的实现
一、实验目的
1、掌握死锁产生的原因和必要条件。
2、掌握银行家算法的实现
二、实验理论基础及教材对应关系
1、处理机调度与死锁。
2、死锁的产生与预防。
3、银行家算法。
三、实验内容与步骤
1、创建C语言工程项目,按照教材上的有关说明,定义相应的数据结构。
intAllocMatrix[5][4]//已经分配资源矩阵
intRequestMatrix[5][4]//需求矩阵
intAvailResource[4]//可用资源向量
intTryProcess[5]//尝试序列
2、给各个数据结构设定合适的初始值。
按照教材课后习题22的内容给上述数据结构设定初始值。
如:
intAllocMatrix[5][4]={//已经分配资源矩阵
{0,0,3,2},
{1,0,0,0},
{1,3,5,4},
{0,3,3,2},
{0,0,1,4}
};
注意:
步骤1、2可同时进行,即利用C语言中的定义变量就可同时初始化的方式进行数值初设。
3、依据银行家算法的描述依次进行资源的试探性分配,直至成功或失败,成功则说明当前状态是安全的;失败后,还应该将资源回到初始状态,并进行另一次试探;只有所有的试探都失败了,才能说明当前状态是不安全的。
通常,这种试探性算法采用递归的方法是很合适的,程序也是很简洁的。
代码片段:
if(AvailResource[0]>=RequestMatrix[k][0]
&&AvailResource[1]>=RequestMatrix[k][1]
&&AvailResource[2]>=RequestMatrix[k][2]
&&AvailResource[3]>=RequestMatrix[k][3])//若资源能使进程ProcessID结束
for(inti=0;i<4;i++)
AvailResource[i]-=AllocMatrix[k][i];//恢复资源
intSearchSecurity(intlevel)//递归函数
{
if(level==4){
……
}
else{
SearchSecurity(level+1);//有条件递归调用自己
}
……
}其余由大家自行完成。
实验6存储管理
实验目的:
存储管理的主要功能之一是合理的分配空间.请求页式管理是一种常用的虚拟存储管理技术.
本实验的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法.
实验内容:
通过随机数产生一个指令序列,共320条指令。
指令的地址按下述原则生成:
50%的指令是顺序执行的;
25%的指令是均匀分布在前地址部分;
25%的指令是均匀分布在后地址部分。
具体的实施方法是:
在[0,319]的指令地址之间随机选取一起点m;
顺序执行一条指令,即执行地址为m+1的指令;
在前地址[0,m+1]中机选取一条指令并执行,该指令的地址为m’;
顺序执行一条指令,其地址为m’+1;
在后地址[m’+2,319]中随机选取一条指令并执行;
重复上述①~⑤,只到执行320条指令。
(2)将指令下列变换成页地址流
设:
①页面大小为1k;
②用户内存容量为4页到32页;
③用户虚存容量为32k。
在用户虚存中,按每k存放10条指令排列虚存地址,即320条指令在虚存①中存放方式为:
第0条~第9条指令为第0页(对应虚存地址为[0,9]);
第10条~第19条指令为第1页(对应虚存地址为[10,19]);
…
第310条~第319条指令为第31页(对应虚存地址为[310,319]);
按以上方式,用户指令可组成32页。
(3)计算并输出下述各种算法在不同内存容量中的命中率。
①先进先出的算法(FIFO);
②最近最少使用算法(LUR);
③最佳淘汰算法(OPT):
先淘汰最不常用的页地址;
④最少访问页面算法(LFR);
⑤最近最不经常使用算法(NUR)。
其中③和④为选择内容。
命中率=1-
在本实验中,页地址流长度为320,页面失效次数为每次访问相应指令时,该指令所对应的页不在内存的次数。
3.随机数产生办法
关于随机数产生办法,linux或UNIX系统提供函数srand()和rand(),分别进行初始化和产生随机数。
例如:
srand();
语句可初始化一个随机数;
a[0]=10*rand()/32767*319+1;
a[1]=10*rand()/32767*a[0];
…
语句可用来产生a[0]与a[1]中的随机数。
实验7文件系统设计
实验目的:
通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能及内部实现。
实验内容: