fork函数
fork函数简介
fork()函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。我把这两个进程分别称之为父进程和子进程。
实验前的准备
1.安装虚拟机VMware,配置系统环境
具体安装过程只需稍微百度一下便可知晓,这里就不过多赘述。
2.学习Linux的命令使用
为了运行forks函数的代码,我们需要提前了解Linux的命令使用
1.命令:cd 目录
cd / 切换到根目录
cd /usr 切换到根目录下的usr目录
cd …/ 切换到上一级目录 或者 cd …
cd ~ 切换到home目录
cd - 切换到上次访问的目录
2.命令:find 目录 参数 文件名称
示例:find /usr/tmp -name ‘a*’ 查找/usr/tmp目录下的所有以a开头的目录或文件
3.命令:kill pid 或者 kill -9 pid(强制杀死进程) pid:进程号
3.拷入代码,运行产生实验结果
注:我的电脑不能直接将原电脑的文件直接拖入虚拟机,所以是通过QQ邮箱来发送和接受代码文件,产生这种情况的原因尚未知晓。
分析fork函数
fork2()
实验结果:
分析:
如图所示的进程图即可说明,每当其运行到fork()函数时,就会分出子进程和父进程,L0在第一个fork()之前,所以只打印一次,而L1在两个fork()之间,则打印两次,而bye在两个fork()后面,所以打印四次。
注:因为子进程和父进程运行随机,不同时间运行时,打印出的结果会不同,打印次序会变化。
fork1()
显示结果:
分析:子进程时pid==0,打印"child …"部分,++x得x == 2,父进程时,pid == 1,打印"parent …"部分,–x得x == 0,而无论是父进程还是子进程,执行玩if语句后都会执行后续的printf(bye …),所以最终的显示结果为四行语句,且显示顺序可以不同。
fork9()
显示结果为:
分析:fork()函数的父进程和子进程的执行顺序随机,图中所示情况为先执行父进程,打印了HP,而后出现了wait()语句,意思为等待子进程结束,所以此时子进程随比父进程满,它的打印仍然是HC先于父进程的CT,最后进程结束后打印bye,下图为流程示意图。
fork7()
显示结果:
分析:从结果上看不出有什么问题,但程序并未终止,父进程有一个无限循环,子进程结束后,如果父进程一直不结束,会变为僵死进程,这时需要杀死它的父进程才能杀死僵死进程。
fork8()
显示结果:
分析:和fork7()一样,虽然结果显示看起来并无问题,但其实程序运行后没有结束,观察程序可知,子进程中有一个无限循环,这时可用kill直接杀死。
fork14()
实验结果:
而后进程会卡死。
分析:孩子进程正常退出时,会向父进程发送 SIGCHLD 信号,signal 函数接收到该信号,调用 handler 函数处理handler 函数等待一个子进程结束,然后 ccount 会减一父进程由于 ccount = N,一开始会陷入死循环,直到子进程全部被回收为止但是如果已有一个子进程先 sleep 结束向父进程发送信号,到父进程处理该信号之前,所有的子进程发送的 SIGCHLD 信号都会被弃,因此这个函数的输出是不确定的,并且如果子进程未全部结束,父进程会一直持续下去,此时挂起当前进程后使用 ps 命令查看则会看到已经结束的子进程会变成僵死进程。
总结
上述的几个fork()函数涉及到几个不同的语句,fork2()是最基本的fork()函数进程,fork1()涉及if()语句,fork7()和fork8()涉及无限循环语句,fork9()涉及wait()函数,而fork16()则与信号有关。通过对上述fork()函数的运行和分析,自己对fork()函数有了一个清晰的认识,懂得了wait()以及信号的理解方式,对今后的学习铺好了基础。