一、 实验目的
1. 加深对进程概念的理解,明确进程和程序的区别。进一步认识并发执行的实质。
2. 了解信号处理。
3. 认识进程间通信(IPC):进程间共享内存。
4. 实现shell:了解程序运行。
二、 实验运行环境
虚拟机VMware下的Ubuntu16.04系统
三、 实验内容
1. 进程的创建实验
2. 信号处理实验
3. 进程间共享内存实验
4. 实现shell的要求
四、 实验过程
①进程的创建实验
(1) 将下面的程序编译运行,并解释现象
编译运行得到的结果如下图:
注意可能得到的结果不止一个,但是每一个结果中都有两个1、四个2、四个3、两个4,这里选取上图的结果来作分析。
可能的原因如下:
这里先用进程树来分析:
接下来是各个进程之间的竞争关系导致输出结果不同:
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。试观察记录屏幕上的显示结果并分析原因。
所编写的程序如下:
编译运行得到的结果如下:
注意:可能的结果有多种,这里选取上图的结果来分析。
原因:
所以:输出结果为acb
(3) 下面程序将在屏幕上输出的字符X、数字1和0各多少个?为什么?
编译运行得到的结果如下:
分析出现该结果的原因:
所以:输出结果为XXXX0
(4) 如果将上面(3)的main函数修改如下,则屏幕上输出的字符X、数字1和0各多少个?为什么?
编译运行得到的结果如下:
注意得到的结果可能不止一个,这里选取上图所得的结果来分析。
可能原因:由于输出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!
所编写的程序如下图:
编译运行所得结果如图:满足实验要求。(不止这种结果)
(b)在上述(a)中的程序中增加语句
signal(SIGINT, SIG_IGN) 和
signal(SIGQUIT, SIG_IGN),观察执行结果并分析原因。这里
signal(SIGINT, SIG_IGN) 和
signal(SIGQUIT, SIG_IGN)分别为忽略“Ctrl Z”键信号以及忽略“Ctrl C”中断信号。
加入两个signal的代码如下:
编译运行的结果如下图:出现该结果的原因是按ctrl c键会被忽略,由于子进程m-p1先被创建,此时会先执行m-p1输出第一条child1,然后再执行m-p2输出第二条child2,最后执行main输出parent
③进程间共享内存实验
完成第三章练习3.10的程序,利用共享内存的方法调用子进程来输出斐波那契数列。
根据要求编写的程序代码如下图:
编译运行可得到下面的结果:注意这里需要加上参数,可以得出程序编写正确,实现了进程间共享内存。
④实现shell的要求
实验要求:
完成课本上第三章的项目:实现shell。除此之外满足下面要求:
根据老师的指导课件,可编写下面的程序实现简单shell
编译运行可得到下面的结果:
命令ls -l:七个字段分别为:
文件属性 文件inode数量 所有者 所属用户组 文件大小 修改时间 文件名
命令ls -L -R:列出某文件夹下的所有文件和目录的详细信息
创建一个新目录并删除(这里先前建了个helloworld.cpp):
编译运行helloworld.cpp然后运行可执行文件helloworld:
按下ctrl c输出命令的历史记录:
输入命令,后面紧接着&,可以使命令在后台运行(光标停止在下一行,不会出现COMMAND->):
最后按下ctrl d退出程序。
五、 实验总结
通过这次实验,我加深了对进程的理解,深刻理解进程之间的竞争与通信!