《操作系统》实验教学大纲
一、基本信息
课程编码 |
350424005 |
课程学时 |
48 |
||
课程类别 |
学科基础课程 |
实验总学时 |
8 |
开出学期 |
5 |
开出单位 |
计算机系 |
适用专业 |
软件工程 网络工程 |
||
二、实验安排
序号 |
实 验 项 目 |
实验学时 |
每组人数 |
实验类型 |
开出要求 |
1 |
实验一 进程管理 |
2 |
1 |
验证 |
必做 |
2 |
实验二 进程通信 |
6 |
1 |
设计 |
必做 |
三、实验目的、内容与要求
实验一 进程管理
(一)实验目的
1.加深对进程概念的理解,明确进程和程序的区别。
2.进一步认识并发执行的实质。
3.分析进程竞争资源的现象,学习解决进程互斥与同步的方法。
(二)实验内容
1.Linux系统中进程的创建。
2.Linux系统中进程的控制。
(三)实验要求
1.掌握Linux系统中进程的创建、控制的实现方法。
2.根据实验内容,在Linux平台上用C语言编程实现,上机调试运行得出实验结果。
3.写出预习报告和实验报告。
实验二 进程通信
(一)实验目的
1.理解和掌握Linux系统中进程通信的基本原理。
2.进一步认识进程软中断通信、管道通信和消息队列通信的实质。
3.分析、设计进程软中断通信、管道通信和消息队列通信的实现方法。
4.掌握进程通信的实现机制。
(二)实验内容
1.设计进程的软中断通信。
2.设计进程的管道通信,实现父子进程的单机通信机制。
3. 设计进程的消息队列通信,实现客户机/服务器通信机制。
(三)实验要求
1.掌握进程软中断通信、管道通信和消息队列通信的设计与实现方法。
2.根据实验内容,在Linux平台上用C语言编程实现,上机调试运行得出实验结果;
3.写出预习报告和实验报告。
四、考核方式
实验成绩占课程总成绩的比重为20%。
考核方式根据实验课考勤、课前预习情况、课上实验能力、原型系统效果验收与实验报告的完成情况综合评分。
每个实验考核:实验预习占30%,实验能力和效果占30%,实验报告占40%。
五、建议教材与教学参考书
1.课程教材
[1] 张尧学. 计算机操作系统教程. 第四版. 北京:清华大学出版社. 2013.10
[2] 赵俊生.操作系统实验指导书.自编.2016
2.教学参考书
[1] 汤小丹.计算机操作系统.第三版.西安: 西安电子科技大学出版社.2008
[2] 徐虹. 操作系统实验指导. 北京: 清华大学出版社.2004
[3] 屠祁. 操作系统基础.第三版.北京: 清华大学出版社.2000
[4] 冯耀霖. 操作系统. 西安: 西安电子科技大学出版社.2001
[5] 左万历.计算机操作系统教程.第二版.北京:高等教育出版社.2004
六、编制说明
编制者: 组长:马志强
执笔人: 编制时间:2019年7月
实验一 进程管理
一、实验目的
1.学会在Linux中利用系统调用fork()创建进程。
2.加深对进程概念的理解,明确进程和程序的区别。
3.进一步认识在系统内进程并发执行的实质。
4.分析进程竞争资源的现象,学习解决进程互斥与同步的方法。
二、实验类型
验证性实验。
三、实验预备知识
1.阅读Linux的sched.h源码文件,加深对进程管理概念的理解。
2.阅读Linux的fork.c源码文件,分析进程的创建过程。
四、实验内容
1.进程的创建
【任务】
编写一段程序,使用系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。
【程序】
#include <stdio.h>
main()
{
int p1,p2;
while((p1=fork())= =-1); /*创建子进程p1,失败时循环*/
if(p1= =0) /*子进程p1创建成功*/
putchar(‘b’);
else /*父进程返回*/
{
while((p2=fork())= =-1); /*创建另一个子进程p2,失败时循环*/
if(p2= =0) /*子进程p2创建成功*/
putchar(‘c’);
else
putchar(‘a’); /*父进程执行*/
}
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析多次执行产生不同实验结果的原因。
2.进程的控制
【任务】
修改已编写的程序,将每个进程的输出由单个字符改为一句话,再观察程序执行时屏幕上出现的现象,并分析其原因。如果在程序中使用系统调用lockf()来给每个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
【程序1】
#include <stdio.h>
main()
{
int p1,p2,i;
while((p1=fork())= =-1);
if(p1= =0)
for(i=0;i<50;i++)
printf(“child %d\n”,i);
else
{
while((p2=fork())= =-1)
if(p2= =0)
for(i=0;i<50;i++)
printf(“son %d\n”,i);
else
for(i=0;i<50;i++)
printf(“daughter %d\n”,i);
}
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析多次执行产生不同实验结果的原因。
【程序2】
#include <stdio.h>
#include <unistd.h>
main()
{
int p1,p2,i;
while((p1=fork())= =-1);
if(p1= =0)
{
lockf(1,1,0); /*加锁*/
for(i=0;i<50;i++)
printf(“child %d\n”,i);
lockf(1,0,0); /*解锁*/
}
else
{
while((p2=fork())= =-1)
if(p2= =0)
{
lockf(1,1,0);
for(i=0;i<50;i++)
printf(“son %d\n”,i);
lockf(1,0,0);
}
else
{
lockf(1,1,0);
for(i=0;i<50;i++)
printf(“daughter %d\n”,i);
lockf(1,0,0);
}
}
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析多次执行产生不同实验结果的原因。
实验二 进程通信
一、实验目的
1.加深对各种进程通信基本工作原理的理解。
2.理解和掌握Linux系统中进程通信API的应用方法。
3.进一步认识进程软中断通信、管道通信和消息队列通信的实质。
4.分析、设计进程软中断通信的实现方法。
5.分析、设计进程的管道通信,实现父子进程的单机通信机制。
6.分析、设计进程的消息队列通信,实现客户机/服务器通信机制。
二、实验类型
设计性实验。
三、实验预备知识
1.阅读Linux进程通信技术(软中断、管道和消息队列)的使用方法。
2.阅读Linux系统中单机和多机通信技术,掌握各种通信技术API的基本应用方法。
四、实验内容
1.进程的软中断通信
【举例1】
编制一段程序,使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按任意字母键和Enter键),当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后,分别输出下列信息后终止:
child process 1 is killed by parent!
child process 2 is killed by parent!
父进程等待两个子进程终止后,输出以下信息后终止:
parent process is killed!
【程序】
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
void waiting(),stop();
int wait_mark;
main()
{
int p1,p2;
while((p1=fork())= =-1); /*创建进程p1*/
if(p1>0)
{
while((p2=fork())= =-1); /*创建进程p2*/
if(p2>0)
{
Printf(“parent run!\n”);
Printf(“p1=%d\n”,p1);
Printf(“p2=%d\n”,p2);
wait_mark=1;
getchar();
kill(p1,16); /*向p1发软中断信号16*/
kill(p2,17); /*向p2发软中断信号17*/
sleep(5); /*父进程睡眠5秒*/
wait(0); /*等待子进程结束,同步*/
wait(0); /*等待另一子进程结束,同步*/
lockf(stdout,1,0); /*标准输出加锁*/
printf(“parent process is killed!\n”);
lockf(stdout,0,0); /*标准输出解锁*/
exit(0); /*父进程终止*/
}
else
{
printf(“p2 run!\n”);
wait_mark=1;
signal(17,stop); /*接收父进程发来的软中断信号17,并转stop*/
waiting();
lockf(stdout,1,0); /*标准输出加锁*/
printf(“child process 2 is killed by parent!\n”);
lockf(stdout,0,0); /*标准输出解锁*/
exit(0); /*子进程p2终止*/
}
}
else
{
printf(“p1 run!\n”);
wait_mark=1;
signal(16,stop); /*接收父进程发来的软中断信号16,并转stop*/
waiting();
lockf(stdout,1,0); /*标准输出加锁*/
printf(“child process 1 is killed by parent!\n”);
lockf(stdout,0,0); /*标准输出解锁*/
exit(0); /*子进程p1终止*/
}
}
void waiting()
{
printf(“waiting begin!\n”);
while(wait_mark!=0);
printf(“waiting end!\n”);
}
void stop()
{
wait_mark=0;
printf(“signal stop!”);
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析产生该实验结果的原因。
【举例2】
在上面任务1中,增加语句signal(SIGINT,SIG_IGN)和语句signal(SIGQUIT,SIG_IGN),观察执行结果,并分析原因。这里signal(SIGINT,SIG_IGN)和signal(SIGQUIT,SIG_IGN)分别为忽略“Ctrl+c”键信号以及忽略中断信号。
【程序】
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int pid1,pid2;
int endflag=0,pf1=0,pf2=0;
void intdelete()
{
kill(pid1,16);
kill(pid2,17);
endflag=1;
}
void int1()
{
printf(“child process 1 is killed by parent!”);
exit(0);
}
void int2()
{
printf(“child process 2 is killed by parent!”);
exit(0);
}
main()
{
int exitpid;
signal(SIGINT,SIG_IGN);
signal(SIGQUIT,SIG_IGN);
while((pid1=fork())= =-1);
if(pid1= =0)
{
printf(“process 1 run!\n”);
signal(SIGUSR1,int1);
signal(16, SIG_IGN);
pause();
exit(0);
}
else
{
while((pid2=fork())= =-1);
if(pid2= =0)
{
printf(“process 2 run!\n”);
signal(SIGUSR2,int2);
signal(17, SIG_IGN);
pause();
exit(0);
}
else
{
printf(“parent run!\n”);
signal(SIGINT,intdelete);
waitpid(-1,&exitpid,0);
printf(“parent process is killed!\n”);
exit(0);
}
}
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析产生该实验结果的原因。
2.进程的管道通信
【举例】
编制一段程序,实现进程的管道通信。使用系统调用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:
child 1 is sending a message!
child 2 is sending a message!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。
【程序】
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int pid1,pid2;
main()
{
int fd[3];
char outpipe[100],inpipe[100];
pipe(fd);
while((pid1=fork())= =-1);
if(pid1= =0)
{
printf(“p1 run!\n”);
lockf(fd[1],1,0);
sprintf(outpipe,”child 1 process is sending a message!”);
write(fd[1],outpipe,50);
sleep(1);
lockf(fd[1],0,0);
exit(0);
}
else
{
while((pid2=fork())= =-1);
if(pid2= =0)
{
printf(“p2 run!\n”);
lockf(fd[1],1,0);
sprintf(outpipe,”child 2 process is sending a message!”);
write(fd[1],outpipe,50);
sleep(1);
lockf(fd[1],0,0);
exit(0);
}
else
{
printf(“parent run!\n”);
wait(0);
read(fd[0],inpipe,50);
printf(“%s\n”,inpipe);
wait(0);
read(fd[0],inpipe,50);
printf(“%s\n”,inpipe);
exit(0);
}
}
}
【执行结果】
同学自己得到实验结果。
【分析原因】
同学自己分析产生该实验结果的原因。
3.进程的消息队列通信
实验要求:
(1)实现客户机与服务器之间的通信程序。
1)基本要求:实现1台客户机对1台服务器;提高要求:实现n台客户机对1台服务器;
2)要求服务器分别接收客户机数据。
3)要求每个客户机与服务器采用消息队列通信机制来发送和接收消息。
(2)测试程序,给出测试结果并进行分析。
(3)书写预习报告和实验报告。
实验提示:
进程间消息队列通信主要用到的四个系统调用如下:
int msgget(key_t key,int msgflg)
int msgctl(int msgqid,int cmd,struct msqid_ds *buf)
int msgsnd(int msgqid,struct msgbuf *msgp, size_t msgsz,int msgflg)
int msgrcv(int msgqid,struct msgbuf *msgp, size_t msgsz,long msgtyp,int msgflg)
包含的头文件如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
【举例】
编制一个客户机进程,定义消息的格式,使用msgget()系统调用创建消息队列,使用msgsnd()和msgrcv()系统调用实现与服务进程之间消息的发送和接收,通信结束后使用msgctl()系统调用删除相关的消息队列。
(1)客户机程序设计
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSGKEY 75
struct msgform{
long mtype;
char mtext[256];
};
main(){
struct msgform msg;
int msgqid,pid,*pint;
msgqid=msgget(MSGKEY,0777);
pid=getpid();
pint=(int *)msg.mtext;
*pint=pid;
msg.mtype=1;
msgsnd(msgqid,&msg,sizeof(int),0);
msgrcv(msgqid,&msg,256,pid,0);
printf(“client:receive from pid%d\n”,*pint);
}
(2)服务器程序设计
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSGKEY 75
struct msgform{
long mtype;
char mtext[256];
}msg;
int msgqid;
main(){
int i,pid,*pint;
extern cleanup();
for(i=0;i<20;i++)
signal(i,cleanup);
msqid=msgget(MSGKEY,0777|IPC_CREAT);
for(;;){
msgrcv(msgqid,&msg,256,1,0);
pint=(int *)msg.mtext;
*pint=pid;
printf(“server:receive from pid%d\n”,*pint);
msg.mtype=pid;
*pint=getpid();
msgsnd(msgqid,&msg,sizeof(int),0);
}
}
void cleanup()
{
msgctl(msgqid,IPC_RMID,0);
exit();
}