操作系统实验指导书.docx
《操作系统实验指导书.docx》由会员分享,可在线阅读,更多相关《操作系统实验指导书.docx(20页珍藏版)》请在冰豆网上搜索。
操作系统实验指导书
操作系统实验指导书
实验1安装Linux操作系统
一、实验目的
在虚拟机Vmware或者VirtualBox上安装Unbuntu9.1操作系统,后续实验都将在此环境上进行。
通过实验,要求:
1、掌握在虚拟机上安装操作系统的方法;
2、学会安装Linux系统;
3、学会启动Linux系统;
4、学会在宿主机WindowsXP操作系统下,与虚拟机上安排的Ubuntu共享文件的方法。
二、实验内容
1、把ubuntu安装至虚拟机上。
●加载安装ubuntu操作系统的ISOIMG文件
●启动ubuntu虚拟机
●按提示分阶段装入系统
2、在Windows下通过网络磁盘来访问ubuntu共享文件夹
●在虚拟系统Ubuntu下新建一个文件夹,右击该文件夹,选择属性,共享,启用“共享此目录”,并允许他人在此共享里写数据。
注:
共享时需要Samba的支持,系统会提示安装。
●安装完成Samba后,需要重启ubuntu才能生效。
此时回到XP时可在网上邻居里看到一个***-desktopserver(Samba,Ubuntu)的共享目录。
●返回WindowsXP系统,右击“网上邻居”,选择“映射网络驱动器”,
●在“浏览”里找到刚才在Ubuntu下共享的文件夹,选择后完成映射,
●这时打开“我的电脑”会发现多了一个“网络驱动器”,如同我们的硬盘一样。
● 这时你可以在XP系统里复制几个文件到相应的网络驱动器,然后进入Ubuntu系统,就能看到我们刚才复制的文件了;当然,我们也可以往ubuntu共享文件夹里放文件,在XP系统使用。
注:
在创建文件共享的时候,注意主机的网卡一定要打开,否则创建共享是不能成功的
实验2Linux系统中程序编辑、编译与调试工具
一、实验目的
1、熟悉使用Linux字符界面、窗口系统的常用命令。
2、熟悉运用Linux常用的编程工具。
3、掌握在Linux操作系统环境上编辑、编译、调试、运行一个C语言程序的全过程。
二、实验内容
1、熟悉开机后登录Linux系统和退出系统的过程;
2、掌握一种Linux的编辑器,特别是字符界面的vi工具的使用(详见VI简易使用手栅);
3、掌握GCC编译器的基本用法(详见GCC使用手册及常用命令行);
4、掌握GDB调试程序的方法(详见GDB调试程序手册)。
要求在实验报告上完整地进行一个数据结构中c程序的调试,源代码不能少于50行。
实验3进程并发与同步
一、实验目的
1、加深对进程概念的理解,区分进程并发执行与串行执行;
2、掌握进程并发执行的原理,理解进程并发执行的特点;
3、了解fork()系统调用的返回值,掌握用fork()创建进程的方法;熟悉wait、exit等系统调用;
4、能利用相应的系统调用实现进程树与进程间的同步。
二、实验内容
1、编写一C语言程序,实现在程序运行时通过系统调用fork()创建两个子进程,使父、子三进程并发执行,父亲进程执行时屏幕显示“Iamfather”,儿子进程执行时屏幕显示“Iamson”,女儿进程执行时屏幕显示“Iamdaughter”。
要求多次连续反复运行这个程序,观察屏幕显示结果的顺序,直至出现不一样的情况为止。
要求有运行结果截图与结果分析
2、连续4个fork()的进程家族树,family1-1.c程序清单如下:
#include
main()
{
fork();
fork();
fork();
fork();
printf(“A\n”);
}
请根据程序运行结果,画出进程家族树,并分析原因。
3、修改程序1,在父、子进程中分别使用wait、exit等系统调用“实现”其同步推进,父进程必须等待儿子进程与女儿进程结束,才可以输出消息。
写出相应的同步控制,并分析运行结果。
4、创建一个子进程,并给它加载程序,其功能是调用键盘命令“ls-l”,已知该键盘命令的路径与文件名为:
/bin/ls。
父进程创建子进程,并加载./child2程序。
写出相应的程序代码并分析程序运行结果。
三、系统调用
创建子进程系统调用:
fork()
格式
intfork();
返回值
=0
创建成功,从子进程返回
>0
创建成功,从父进程返回,其值为子进程的PID号
=-1
创建失败
子进程创建时操作系统的工作:
✧检查同时运行的进程数目,若超过系统设定值,则创建失败,返回-1;
✧为子进程分配进程控制块task_struct结构,并赋予唯一进程标识符pid;
✧子进程继承父进程打开的所有文件及资源,对父进程的当前目录和所有已打开系统文件表项中的引用记数加1;
✧为子进程创建进程映像:
⏹创建子进程映像静态部分:
复制父进程映像静态部分
⏹创建子进程映像动态部分:
初始化task_struct结构
⏹结束创建,置子进程为内存就绪状态,插入就绪队列,作为一个独立的进程被系统调度。
✧若调用进程(父进程)返回,则返回创建的子进程标识符pid值(此时返回值>0);
✧若子进程被调度执行,则将其U区计时字段初始化然后返回(此时返回值=0)。
进程睡眠系统调用:
sleep()
格式
sleep(n);
参数
n表示延时的秒数
功能
进程睡眠n秒
进程终止系统调用:
exit(status)
格式
voidexit(intstatus);
参数
status是子进程向父进程发送的终止信息,父进程使用wait()系统调用来接收这个信息
头文件
#include
功能
将进程置僵死状态
释放其所占有的资源
向父进程发本进程死信号,并发送信息status给父进程,将自己及自己的子进程运行CPU的时间总和留待父进程使用wait()收集
子进程终止时操作系统做以下工作:
✧关闭软中断:
因为进程即将终止而不再处理任何软中断信号;
✧回收资源:
关闭所有已打开文件,释放进程所有的区及相应内存,释放当前目录及修改根目录的索引节点;
✧写记帐信息:
将进程在运行过程中所产生的记帐数据(其中包括进程运行时的各种统计信息)记录到一个全局记帐文件中;
✧置该进程为僵死状态:
向父进程发送子进程死的软中断信号,将终止信息status送到指定的存储单元中;
✧转进程调度:
因为此时CPU已经被释放,需要由进程调度进行CPU再分配。
父进程等待子进程终止系统调用:
wait()与waitpid()
格式1
pid_twait([int*stat_addr,]0);
参数
*stat_addr中存放exit()所发来终止信号stat的值。
返回值
>=0
表示有子进程终止,其值为终止子进程的pid号
=-1
表示无子进程终止
头文件
#include
#include
功能
父进程使用它等待任意一个子进程终止,如果在执行wait()之前已经有一个子进程结束了,则对其做善后处理,并返回子进程的pid号,如果没有则返回-1,该进程阻塞,插入等待子进程终止的队列,当有子进程终止时被唤醒。
在&stat_addr中保留了子进程僵死时的终止信息(不是返回值)。
注意:
一个wait()只能用来等待一个子进程终止,如果等待多个子进程终止则需要使用多个wait()。
格式2
pid_twaitpid(pid_tpid,int*stat_addr,intoptions);
参数
pid=0
等待与父进程同组的子进程
pid=-1,options=0
等同于wait(),等待任意子进程
pid>0
等待给定pid号的子进程
功能
等待指定pid的子进程终止
说明:
1)若父进程仅仅只是等待任意一个子进程结束,而不需要取子进程发来的信号,则可以简单地使用wait(0)。
2)如果该进程没有创建自己的子进程就不能使用wait()或waitpid(),否则系统会返回一个出错信息。
3)如果要取子进程执行exit()后所发来的终止信号stat,可以使用*stat来取该变量中的值,而不能使用wait()的返回值,因为wait()的返回值是该终止子进程的pid号。
将指定的可执行文件加载到指定进程映像中,覆盖该进程中原有的程序
系统调用:
execl()、execle()、execlp()、execv()、execve()与execvp()
功能
将一个指定的程序装入调用它的进程的映像中,用这个可执行文件的副本去覆盖该进程的程序空间,从而改变调用进程的执行代码,使调用进程执行新引入的可执行程序(二进制代码文件)
内核在响应这组系统调用后做以下工作:
1)根据给出的路径名找到指定的可执行文件,检查该文件是否可执行,用户是否具有执行权限(该文件必须是编译连接后的二进制代码)。
2)将该文件载入到调用它的进程映像中覆盖其原来的程序。
3)为该程序的执行设置参数数组和环境变量。
4)启动该进程进入新的程序入口点去执行。
此组函数执行时,如果加载成功则直接执行,没有返回;若加载不成功则返回-1。
格式1
execv(file,argv)
参数
char*file
指向文件全名(路径名/文件名)的指针
char*argv[n]
指向命令及参数的指针
功能
1)执行参数指定的命令或文件。
2)用该命令或可执行文件的副本覆盖调用它的子进程的映像
返回值
=-1
表示错误返回
头文件
#include
格式2
execl(“路径名/文件名”,0)
说明
功能、返回值、头文件均同格式1
使用方法:
1)事先准备好子进程要执行的程序,并将它编译连接成可执行文件,记下该文件的路径名和文件名。
如果不带参数则可以直接使用execl(),带参数则使用execv()。
2)在父进程创建子进程之前,在程序中事先定义子进程要执行的程序文件的文件标识符path和参数数组argv[],其中的环境值可以用NULL取代。
如果不带参数使用execl(),则这一步可以不做。
3)创建子进程后,在子进程的分支中,如果不带参数使用execl(filepath,0),如果带参数则使用execv(filepath,argv)来实现用指定的程序filepath覆盖子进程映像中原有的程序。
实验4进程通信
一、实验目的
1、加深理解进程通信的方法与原理;
2、掌握如何利用管道机制、消息缓冲队列、共享存储区机制进行进程间的通信。
二、实验内容
1、了解系统调用pipe()、msgget()、msgsnd()、msgrcv()、msgctl()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。
2、编写一C语言程序,使其用管道来实现父子进程间通信。
子进程向父进程发送字符串“issendingamessagetoparent!
”;父进程则从管道中读出子进程发来的消息,并将其显示到屏幕上,然后终止。
3、运行该程序,观察、记录并简单分析其运行结果。
三、有名管道、无名管道系统调用
1、创建无名管道的系统调用
创建无名管道的系统调用:
pipe()
格式
intpipe(int管道名[2]);
返回值
0
正确返回
1
错误返回
参数说明
管道名[1]:
为写入端
管道名[2]:
为读出端
功能
创建一个管道名为指定名称的无名管道,以便于创建管道的进程及其子孙进程共享
头文件
include
●当进程向管道中写时,数据就复制不予考虑了共享的数据页;
●从管道中读时,字节从共享页中按照FIFO的顺序复制出来。
●当所有进程完成管道的操作后,管道的i结点和共享数据页被释放。
2、读写管道的系统调用
读写管道的系统调用:
write()、read()
格式
write(管道名[1],buf,size)
read(管道名[0],buf,size)
参数说明
buf:
程序中定义的字符型数组或缓冲区;
size:
读写的信息长度
说明
管道为临界资源,父子进程之间除了需要读写同步以外,在对管道进行读写操作时还需要互斥进入。
为了保证管道操作过程中不至于因为用户的疏忽而死锁,Linux采用以下措施来避免死锁:
●当进程因读或写等待时,要检查管道的另一端是否已经关闭,如果发现对方已经关闭则直接返回,不再等待。
●当进程关闭管道时,要检查管道的另一端是否正处于等待状态,如果是,则要先唤醒对方,然后再关闭管道。
●如果进程需要实现互斥,因为管道是文件,可以使用对文件上锁和开锁的系统调用。
3、文件上锁、开锁系统调用
文件上锁、开锁系统调用:
lockf()
格式
lockf(files,function,size)
参数说明
files
是需要加以封锁的文件描述符,此处可以是管道的读写端口
function
为1表示上锁,为0表示开锁
size
表示锁定或开销的字节数,其值为0则表示文件全部内容
4、命名管道创建系统调用
命名管道创建系统调用:
mkfifo()
格式
intmkfifo(constchar*pathname,mode_tmode);
功能
专门用于创建FIFO
参数说明
mode
权限值,如0777表示所有用户都可读、可写、可执行
返回值
正确返回0,错误返回-1.
头文件
#include
#include
mknod用于创建一般的设备文件
四、Linux消息缓冲通信的系统调用
1、创建一个消息队列或获取已存在消息队列的标识
创建消息队列/获取已存在消息队列的系统调用:
msgget()
命令格式
intmsgget(key_tkey,intmsgflag);
功能
创建标识为key值的消息队列或者获取已存在的消息队列的描述符msgid
返回值
正确返回该消息队列的描述符msgid;
错误返回-1。
语句格式
msgid=msgget(key,msgflag);
参数说明
msgqid
该系统调用返回的消息队列描述符,-1表示失败;
key
用户指定的消息队列标识符,为一正整数,其值可以由用户指定,如果使用IPC_PRIVATE则由系统产生key值;
flag
用户设置的标志或访问方式,其值由操作权限和控制命令进行或运算得到
头文件
#include
#include
操作允许权八进制数
操作允许权八进制数
用户可读0400
用户可写0200
小组可读0040
小组可写0020
其他可读0004
其他可写0002
控制命令值
IPC_CREAT(创建)0001000
2、发送一条消息到指定的消息队列
发送一条消息到指定的消息队列系统调用:
msgsnd()
命令格式
intmsgsnd(intmsgid,structmsgbuf*msgp,intsize,intflag);
功能
发送一个消息给指定描述符的消息队列。
将msgp所指向的msgbuf中的消息复制到消息数据结构并挂到指定消息队列尾,唤醒等待消息的进程
参数说明
msgqid
执行msgget()返回的消息队列的描述符
msgp
指向用户存储区的一个消息缓冲msgbuf的指针,在msgbuf中包含消息类型和消息正文
size
由msgp指向的数据结构中字符数组的长度(消息长度)
flag
规定当核心用尽内部空间时应执行的动作。
例如:
若在flag中设置了IPC_NOWAIT,则当消息队列中的字节数超过最大值msgsnd立即返回,否则msgsnd睡眠。
flag可置0。
头文件
#include
#include
3、从消息队列接收消息
从消息队列接收消息的系统调用:
msgrcv()
命令格式
intmsgrcv(intmsgid,structmsgbuf*msgp,intsize,inttype,intflag);
功能
从指定的消息队列接收一个消息。
将消息复制到msgp所指的msgbuf中,从消息队列中删除此消息,若消息未到则调用进程阻塞,并将该进程插入等待消息队列尾。
参数说明
msgid
消息队列描述符;
msgp
用来存放要接收消息的用户msgbuf的地址;
size
msgp中数据数组的大小;
type
用户要读取的消息类型
=0表示接收队列的第一个消息;
>0表示接收类型type的第一个消息;
<0表示接收小于或等于|type|的最低类型的第一个消息
flag
规定若该队列无消息,操作系统核心应当做什么,可设置为0.
头文件
#include
#include
4、对消息队列的操作
对消息队列操作的系统调用:
msgctl()
命令格式
intmsgctl(intmsgid,intcmd,structmsgid_ds*buf);
功能
查询一个消息队列的状态;设置或修改它的状态;撤消一个消息队列
返回值
函数调用成功返回0;不成功返回-1.
参数说明
msgid
该消息队列的描述符;
cmd
规定命令的类型
●IPC_STAT查询消息队列状态,将与msgid相关联的消息队列首标读入buf;
●IPC_SET设置或修改消息队列状态,设置有效用户、组标识、操作允许权,及字节数;
●IPC_RMID撤消描述符为msgid的消息队列;
buf
含有控制参数或查询结果的用户缓冲区的地址,可设置为0
头文件
#include
#include
注意:
设置和撤消消息队列的进程需要有一定的权限,如超级用户、具有有效用户ID、符合msg_perm权限设置等。
四、共享内存通信的系统调用
1、创建或获取一个共享内存
创建/获取一个共享内存的系统调用:
shmget()
命令格式
shmget(key,size,flag);
功能
获得一个内部标识为shmid的共享存储区
说明
该函数创建的共享内存区域并没有立即分配物理内存,而是创建一个文件对象shm_file来描述该区域。
Shm_file文件并不属于磁盘文件,而是由内存页面组成,因此当系统亲面时,其中的内容也随之消失。
语句格式
intshmid=intshmget(key_tkey,intsize,intflag);
参数说明
key
共享存储区关键字,可以由用户指定,如果使用IPC_PRIVATE,则其值由系统产生。
size
存储区的大小(字节数)。
如果存储区定义为字符型,则大小为定义的字符个数;如果存储区定义为整型,大小可以使用sizeof(int)加以定义。
flag
用户设置的标志或访问方式,与消息缓冲shmget中的含义相同。
可以使用066|IPC_CREAT,表示任意进程可读可写。
返回值
正确时返回共享存储区的内部标识符shmid,错误时返回-1。
头文件
#include
#include
2、将共享内存附接到进程的虚拟地址空间
将共享内存附接到进程虚拟地址空间的系统调用:
shmat()
命令格式
字符型共享内存
shmat(intshmid,char*shmaddr,intmsgflg,ulong*raddr);
数值型共享内存
shmat(intshmid,int*shmaddr,intmsgflg,ulong*raddr);
功能
逻辑上将内部标识符为shmid的共享存储区附接到进程的虚拟地址空间shmaddr
语句格式
字符型共享内存
viraddr=(char*)shmat(shmid,shmaddr,shmflag);
数值型共享内存
viraddr=(int*)shmat(shmid,shmaddr,shmflag);
参数说明
shmid
共享存储区的描述符,可以由shmget()的返回值得到。
shmaddr
用户提供的共享存储区附接的虚地址。
若shmaddr为0,则由系统选择一个适当的地址来附接该存储区。
shmflag
规定了对该存储区的操作权限,以及系统是否要对用户规定的地址执行舍去操作。
如果shmflag中设置了SHM_RND,则表示操作系统在必要时舍去这个地址;如果设置SHM_RDONLY则表示只允许读,shmflag为0表示可读可写。
viraddr
附接的虚地址。
若定义为char*viraddr,则该共享内存作为字符存储区使用;若定义为int*viraddr,则该共享内存作为整型存储区使用。
返回值
正确时返回共享存储区附接后的虚地址,错误时返回-1。
头文件
#include
#include
3、将共享内存从进程的地址空间断开
将共享内存从进程地址空间断开的系统调用:
shmdt()
命令格式
shmdt(viraddr);
功能
将一个共享存储区从指定进程的虚拟地址空间断开
参数说明
viraddr
系统调用shmat()所返回的虚地址
返回值
正确时返回0,错误时返回-1。
头文件
#include
#include
4、对共享内存的操作
对共享内存操作的系统调用:
shmget()
命令格式
shmctl(intshmid,intcmd,structshmid_ds*buf)
功能
对与共享存储区关联的各种参数进行操作,从而对共享存储区进行控制,包括删除共享存储区
参数说明
shmid
共享存储区的内部标识符,由shmget()调用返回
buf
用户级数据结构地址,其结构类型与系统定义的shmid_ds一致,可以用0
cmd
规定操作的类型。
其规定如下:
●IPC_STAT:
返回包含在指定的shmid相关数据结构中的状态信息,并把它放置在用户存储区中的*buf指针所指的数据结构中。
执行此命令的进程必须有读取允许权。
●IPC_SET:
对于指定的shmid,为它设置有效用户和小组标识符和操作存取权。
●IPC_RMID:
删除指定的shmid以及与它相关的共享存储区的数据结构。
●SHM_LOCK:
在内存中锁定指定的共享存储区,必须是超级用户才可以进行此项操作。
返回值
正确时返回0,错误时返回-1。
头文件
#include
#include