admin 管理员组文章数量: 1184232
2024年1月14日发(作者:csdn官网电脑版)
实验二实验报告
一、实验名称
进程创建与通信
二、实验目的
(1) 加深对进程概念的理解,理解进程和程序的区别。
(2) 认识并发进程的实质。分析进程争用资源的现象,学习解决进程互斥的方法。
(3) 认识并发进程的软中断通信。掌握使用软中断控制进程的编程技术
(4) 掌握管道通信原理。
(5) 通过编写 Linux 消息发送和接收程序,了解和熟悉 Linux 消息通信机制
(6) 通过编写共享存储区的通信程序,理解 Linux 共享存储区机制。
三、实验环境
(1) 硬件环境:Intel Pentium III 以上 CPU,128MB 以上内存,2GB 以上硬盘
(2) 软件环境:Ubuntu 13.04 操作系统。
注:Ubuntu 是 Linux 的一个免费发行的流行版本,系英国"科能软件股份有限公司
(Canonical)"开发
四、实验内容
(1)编写一段程序,使用系统调用 fork()创建两个子进程 p1 和 p2。p1 显示字符'b',p2
显示字符'c',父进程显示字符'a',父进程和两个子进程并发运行。观察并记录屏幕上的
显示结果,分析原因。(进程创建e202.c)
(2)编写一段程序, 实现下列功能:创建两个子进程。用户按中断键(Ctrl-C),被父进程捕
获。父进程捕获用户中断键后向子进程发信号,让两个子进程显示下列信息后终止:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
父进程等待两个子进程终止后,自己输出下列信息后终止:
Parent process is killed!(进程控制e203.c)
(e800.c)
(3) 编写一段程序, 实现进程的管道通信。使用系统调用 fork()创建两个子进程 p1 和
p2。
使用系统调用 pipe()建立一条管道。两个子进程 p1 和 p2 分别向管道各写一句话:
child 1 is sending a message!
child 2 is sending a message!
父进程从管道中读出来自两个子进程的信息,显示在屏幕上。(进程通信 e204.c)
五、实验原理
(1) 编译与连接程序
Linux 下常用的 C/C++语言编译器是 GCC(GNU Compiler Collection),它是
GNU 项目中符合 ANSI C 标准的编译系统,能够编译 C、C++等语言编写的程序。它除了功能强大,结构灵活外,还可以通过不同的前端模块来支持各种语言,如 Java、Pascal
等。GCC 编译过程分为四个阶段:预处理(Pre-Processing)编译(Compiling)汇编
(Assembling)连接(Linking)
(2)fork()系统调用
fork 的功能是创建子进程。调用 fork 的进程称为父进程
(3)wait()系统调用
wait 的功能是等待子进程结束。发出 wait 调用的进程只要有子进程,就会睡眠
直到子进程中的一个终止为止。若没有子进程,则该调用立即返回
(4)信号是一种软件中断,用来通知进程发生了异步事件。进程之间可以互相通过系统调用
kill 发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个
事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
(5)所谓管道,就是将一个进程的标准输出与另一个进程的标准输入联系在一起,是进程通信的一种方法。创建管道使用系统调用 pipe()。管道两端是固定了任务的,一端只能用于读,另一端只能用于写。
(6)程序的并发执行具有随机性和不可再现性。程序并发执行会导致资源共享和资源竞争,各程序向前执行的速度会受资源共享的制约。程序的动态执行过程用进程这个概念来描述。由于向前推进的速度不可预知,所以多个进程并发地重复执行,整体上得到的结果可能不同。但要注意,就其中某单个进程而言,其多次运行结果是确定的。
(7)并发运行的进程之间,可以通过信号进行同步,也可以通过管道、消息通信机制、共享存储机制进行通信。
六、实验步骤
【任务 1】
编写一段程序,使用系统调用 fork()创建两个子进程 p1 和 p2。
P1显示字符'b',p2显示字符'c',父进程显示字符'a',父进程和两个子进程并发运行。观察并记录屏幕上的显示结果,分析原因。
(1)程序设计
用while 语句控制 fork()直到创建成功。用if语句判别是在子进程中还是在父进程中。程序运行后会创建三个进程,它们分别是子进程 p1、p2、父进程。这三个进程并发运行。假定子进程有些任务要做,完成这些任务要花一定时间,因此可以用一个延时函数简单地模拟这些任务。
(2)上机操作
用 gedit 输入上述源代码,取名为 e202.c。
编译
gcc –o e202 e202.c
运行
./e202
按向上的光标键、回车,运行刚才的程序。快速重复这个步骤,观察并记录结果。
(3)问题
屏幕上是否有时显示 bac,有时显示 bca,…。为什么会这样呢?
【任务 2】
编写一段程序, 实现下列功能:创建两个子进程。用户按中断键(Ctrl-C),被父进程捕
获。父进程捕获用户中断键后向子进程发信号,让两个子进程显示下列信息后终止:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
父进程等待两个子进程终止后,自己输出下列信息后终止:
Parent process is killed!
(1)参考程序
使用 while 语句控制 fork()创建两个字进程 p1 和 p2。父进程使用系统调用
signal()捕捉用户的中断键。若用户按下中断键 Ctrl-C,则用 kill()向 p1、p2
发自定义信号。 然后用 wait()等待 p1、p2 结束。p1、p2 用 signal()捕捉父进程的自定义信号(信号16和17),捕到后显示信息,然后用 exit()终止自己。
(2)上机操作
用 gedit 输入源代码。
编译、运行,观察屏幕,记录结果。
(3) 问题:为什么两个子进程没有显示预期的信息?
【任务 3】
编写一段程序, 实现进程的管道通信。使用系统调用 fork()创建两个子进程 p1 和 p2。
使用系统调用 pipe()建立一条管道。两个子进程 p1 和 p2 分别向管道各写一句话:
child 1 is sending a message!
child 2 is sending a message!
父进程从管道中读出来自两个子进程的信息,显示在屏幕上。
(2)上机操作
编辑、编译、运行、观察屏幕、记录结果。
七、实验结果
【任务 1】
#include
void delay(int x) //延时函数
{
int i,j;
for(i=0;i for(j=0;j } int main() { int p1,p2; while((p1=fork())==-1); //创建子进程 p1 if(p1==0) //子进程 p1 创建成功 { delay(10); //子进程 p1 延时 putchar('b'); //子进程 p1 显示字符'b' }else{ while((p2=fork())==-1); //创建子进程 p2 if(p2==0) //子进程 p2 创建成功 { delay(10); //子进程 p2 延时 putchar('c'); //子进程 p2 显示字符'c' }else{ delay(100); //父进程延时 putchar('a'); //父进程显示字符'a' } } return 0; } 实验截图: 可以看出,以a,b为开头的a,b,c的各种组合都可能会出现,为什么没有出现c开头? 因为内存资源是随机分配且独占的,只有当一个进程运行结束才会运行下一个进程。 只能ab为开始的原因是当p1创建时,父进程和p1抢占资源。得到资源的一个先运行结束,所以只能是a或者b为开头。另一个再和进程p2争夺资源,输出另外两个字母。 从多次结果来看,资源的分配优先概率a>b>c 任务2: #include #include #include void waiting(); void stop(); int wait_mark; int main() { int p1, p2; while ((p1 = fork()) == -1) ; if (p1 > 0) { while ((p2 = fork()) == -1) ; if (p2 > 0) { printf("parentn"); wait_mark = 1; signal(SIGINT, stop); waiting(); kill(p1, 16); kill(p2, 17); wait(0); wait(0); printf("parent process is kill!n"); exit(0); } else { printf("p2n"); signal(SIGINT,SIG_IGN); wait_mark = 1; //置等待标志 signal(17, stop); //捕捉父进程信号 17,调用信号处理函数 stop() waiting(); //忙等待 lockf(stdout, 1, 0); //锁住标准输出 stdout printf("child process 2 is killed by prent!n"); lockf(stdout, 0, 0); //解锁 exit(0); //子进程 p2 结束自己 } } else { printf("p1n"); signal(SIGINT,SIG_IGN); wait_mark = 1; //置等待标志 signal(16, stop); //捕捉父进程信号 16,调用信号处理函数 stop() waiting(); //忙等待 lockf(stdout, 1, 0); //锁住标准输出 stdout printf("child process 1 is killed by parent!n"); lockf(stdout, 0, 0); //解锁 exit(0); //子进程 p2 结束自己 } return 0; } void waiting() //忙等待函数 { while(wait_mark!=0); //忙等待 } void stop() { wait_mark=0; //清除忙等待标志 } 实验截图: 两个子进程和父进程都显示了预期的信息 任务3: #include #include #include int pid1, pid2; int main() { int fd[2]; char OutPipe[100], InPipe[100]; pipe(fd); while((pid1 = fork()) == -1); if(pid1 == 0){ printf("p1n"); 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("p2n"); 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("parentn"); wait(0); read(fd[0], InPipe, 50); printf("%sn", InPipe); wait(0); read(fd[0], InPipe, 50); printf("%sn", InPipe); exit(0); } } return 0; } 编辑、编译、运行、观察屏幕、记录结果。 实验截图: 八、实验总结 任务一: 1.学会了linux下使用gcc编译器对c语言程序编译:gcc -o (文件名) (新文件名)。 2.学会进程的基本概念和运行方式,通过fork()新建子进程,并从父程序的fork()下一行开始运行,且返回值为0 任务二: 1. 通过调用signer函数,通过监听信号对进程进行操作。需要注意的是,所有的进程都会监听信号,需要把无需听某个信号的进程进行处理防止意外退出。 任务三: 1. 学习进程间通信的基本理论和大致方法 2. 通过pipe管道进行进程间单条信息的通信 九、教师评阅意见
版权声明:本文标题:操作系统实验-进程创建与通信 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1705182993a475870.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论