中山大学软件工程操作系统实验一报告

欢迎访问我的个人博客:Talk is cheap. Show me the code!。我相信会有所收获的。

实验一 进程和进程通信


一、 实验目的
1. 加深对进程概念的理解,明确进程和程序的区别。进一步认识并发执行的实质。
2. 了解信号处理。
3. 认识进程间通信(IPC):进程间共享内存。
4. 实现shell:了解程序运行。


二、 实验运行环境
虚拟机VMware下的Ubuntu16.04系统


三、 实验内容
1. 进程的创建实验
2. 信号处理实验
3. 进程间共享内存实验
4. 实现shell的要求


四、 实验过程
①进程的创建实验
(1) 将下面的程序编译运行,并解释现象

中山大学软件工程操作系统实验一报告_第1张图片

编译运行得到的结果如下图:

中山大学软件工程操作系统实验一报告_第2张图片

注意可能得到的结果不止一个,但是每一个结果中都有两个1、四个2、四个3、两个4,这里选取上图的结果来作分析。
可能的原因如下:
这里先用进程树来分析:
中山大学软件工程操作系统实验一报告_第3张图片
接下来是各个进程之间的竞争关系导致输出结果不同:
1. 首先执行父进程main,它创建子进程m-p1,进而输出1,再创建子进程m-p2,再输出2,然后执行if判断,此时pid1不为0,所以再输出4。main执行完毕,此过程输出1、2、4;
2. 两个子进程相互竞争,先执行子进程m-p2,它执行后面的代码,先输出2,然后执行if判断,此时该子进程继承了父进程main的pid1值,pid1不为0,所以输出4。m-p2执行完毕,此过程输出2、4;
3. 接着执行子进程m-p1,先输出1,再创建一个子进程m-p1-p2,继续输出2,然后执行if判断,此时pid1为0,创建子进程m-p1-p3,然后输出3。m-p1执行完毕,此过程输出1、2、3;
4. 然后执行子进程m-p1-p3,输出3。m-p1-p3执行完毕;
5. 接着执行m-p1-p2,先输出2,然后执行if判断,此时pid1为0,创建子进程m-p1-p2-p3,输出3。m-p1-p2执行完毕,此过程输出2、3;
6. 最后执行子进程m-p1-p2-p3,直接输出3。m-p1-p2-p3执行完毕。

所以:该结果为1、2、4、2、4、1、2、3、3、2、3、3.


(2) 编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符a;子进程分别显示字符b和字符c。试观察记录屏幕上的显示结果并分析原因。

所编写的程序如下:

中山大学软件工程操作系统实验一报告_第4张图片

编译运行得到的结果如下:

这里写图片描述

注意:可能的结果有多种,这里选取上图的结果来分析。
原因:

  1. 首先创建父进程main,执行相应代码,先创建一个子进程m-p1,然后执行if判断,此时pid1不为0,创建子进程m-p2,继续执行if判断,此时pid2不为0,所以输出a,父进程main执行完毕。
  2. 接着子进程m-p1和m-p2竞争,先执行m-p2,此时pid2为0,所以输出c,子进程m-p2执行完毕。
  3. 最后执行子进程m-p1,此时pid1为0,输出b,m-p1执行完毕。

所以:输出结果为acb


(3) 下面程序将在屏幕上输出的字符X、数字1和0各多少个?为什么?

中山大学软件工程操作系统实验一报告_第5张图片

编译运行得到的结果如下:

这里写图片描述

分析出现该结果的原因:

  1. 首先创建父进程main,执行相应代码,先创建子进程m-p1,此时a=1,进入for循环输出两个X,执行if判断,此时pid不为0,所以不输出a的值,main执行完毕,此过程输出XX。
  2. 接下来执行子进程m-p1,此时直接进入for循环,不会改变a的值,即之前父进程main对a赋值为1的语句不会在子进程中执行,a还是为0,进入for循环后输出两个X,然后执行if判断,此时pid为0所以输出a的值为0,m-p1执行完毕,此过程输出XX0。

所以:输出结果为XXXX0


(4) 如果将上面(3)的main函数修改如下,则屏幕上输出的字符X、数字1和0各多少个?为什么?

中山大学软件工程操作系统实验一报告_第6张图片

编译运行得到的结果如下:

这里写图片描述

注意得到的结果可能不止一个,这里选取上图所得的结果来分析。
可能原因:由于输出X的时候是没有换行的,输出X的时候是将X保存在一个缓冲区里等程序结束后才输出的,在fork()调用时会复制缓冲区,因此父进程在第一次循环创建一个子进程时,这个子进程的缓冲区已经有了一个X,之后再输出一个X,也就是这个子进程也会输出两个X。
由程序代码分析可知父子进程共有4个,所以共有8个X被输出,父进程的pid[0]和pid[1]都不为0,所以不会输出a的值,而三个子进程中一个pid[0]==0,a=1;一个子进程pid[1]==0,a=1;另一个子进程pid[0]==pid[1]==0,但是a=0,所以输出结果中有两个1和两个0

所以:输出结果为XXXX1 XX1 XX0 0


②信号处理实验
(a)编写一段程序,使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按Ctrl C键),当捕捉到中断信号后,父进程调用kill()向两个子进程发出信号,子进程捕捉到信号后,分别输出下面信息后终止:
child process 1 is killed by parent!
child process 2 is killed by parent!
父进程等待两个子进程终止后,输出以下信息后终止:
parent process is killed!

所编写的程序如下图:

中山大学软件工程操作系统实验一报告_第7张图片
中山大学软件工程操作系统实验一报告_第8张图片

编译运行所得结果如图:满足实验要求。(不止这种结果)

这里写图片描述
(b)在上述(a)中的程序中增加语句
signal(SIGINT, SIG_IGN) 和
signal(SIGQUIT, SIG_IGN),观察执行结果并分析原因。这里
signal(SIGINT, SIG_IGN) 和
signal(SIGQUIT, SIG_IGN)分别为忽略“Ctrl Z”键信号以及忽略“Ctrl C”中断信号。

加入两个signal的代码如下:

中山大学软件工程操作系统实验一报告_第9张图片

编译运行的结果如下图:出现该结果的原因是按ctrl c键会被忽略,由于子进程m-p1先被创建,此时会先执行m-p1输出第一条child1,然后再执行m-p2输出第二条child2,最后执行main输出parent

中山大学软件工程操作系统实验一报告_第10张图片


③进程间共享内存实验
完成第三章练习3.10的程序,利用共享内存的方法调用子进程来输出斐波那契数列。

根据要求编写的程序代码如下图:

中山大学软件工程操作系统实验一报告_第11张图片
中山大学软件工程操作系统实验一报告_第12张图片

编译运行可得到下面的结果:注意这里需要加上参数,可以得出程序编写正确,实现了进程间共享内存。

中山大学软件工程操作系统实验一报告_第13张图片
这里写图片描述


④实现shell的要求
实验要求:
完成课本上第三章的项目:实现shell。除此之外满足下面要求:

  • 在shell下,按ctrl c时不会终止shell;
  • 实现程序的后台运行。

根据老师的指导课件,可编写下面的程序实现简单shell

中山大学软件工程操作系统实验一报告_第14张图片
中山大学软件工程操作系统实验一报告_第15张图片
中山大学软件工程操作系统实验一报告_第16张图片
中山大学软件工程操作系统实验一报告_第17张图片
中山大学软件工程操作系统实验一报告_第18张图片
中山大学软件工程操作系统实验一报告_第19张图片
中山大学软件工程操作系统实验一报告_第20张图片
中山大学软件工程操作系统实验一报告_第21张图片
中山大学软件工程操作系统实验一报告_第22张图片

编译运行可得到下面的结果:

这里写图片描述
这里写图片描述

命令ls -l:七个字段分别为:
文件属性 文件inode数量 所有者 所属用户组 文件大小 修改时间 文件名

这里写图片描述

命令ls -L -R:列出某文件夹下的所有文件和目录的详细信息

中山大学软件工程操作系统实验一报告_第23张图片

创建一个新目录并删除(这里先前建了个helloworld.cpp):

中山大学软件工程操作系统实验一报告_第24张图片

编译运行helloworld.cpp然后运行可执行文件helloworld:

这里写图片描述

按下ctrl c输出命令的历史记录:

中山大学软件工程操作系统实验一报告_第25张图片

输入命令,后面紧接着&,可以使命令在后台运行(光标停止在下一行,不会出现COMMAND->):

这里写图片描述

最后按下ctrl d退出程序。


五、 实验总结

  1. 第一个实验是关于创建进程的实验,刚开始接触进程,对进程之间的相互竞争非常陌生,尤其看到同一个程序出现了很多种结果感觉很不可思议,最后仔细分析出现每一种结果的原因初步认识了进程间的相互竞争。
  2. 第二个实验是关于信号处理的实验。根据老师的指导代码,可编写出正确的程序,进一步理解了进程之间的竞争以及程序处理信号的机制。
  3. 第三个实验是关于进程间共享内存的实验,初步认识进程间如何通过内存共享进行通信。本身斐波那契数列是常见的算法,但是在此题中我们需要思考数据的处理,怎么让一个进程的数据段分享给另一个进程,让另一个进程使用相同的数据并返回给原进程。通过老师的指导课件,我们知道shmget用来创建或打开共享存储区,shmat用来连接共享存储区,shmdt用来拆除共享存储区连接,shmctl用来共享存储区控制,所以可通过这些函数实现共享内存。
  4. 第四个是实现一个简单shell的实验。这个比较有难度,还好老师提供的指导代码很多,我们只要实现ctrl c输出历史记录中的命令以及其他一些基本东西。 主要的困难在于怎么存储这些记录,这里费了好多功夫理解,最后采用了一个二维数组来存储。具体代码可见上面第四部分的图或者代码文件夹中。

通过这次实验,我加深了对进程的理解,深刻理解进程之间的竞争与通信!

你可能感兴趣的:(操作系统)