前一章文章我们简单的说了一下父子进程以及fork函数,那么fork函数创建的新进程与原进程有什么联系呢?如果其中一方结束了会怎么样?他们真的形同父子吗?他们的数据是否共享?以及一些其他的进程问题,这篇文章我们会讲到。
一、父子进程
通过fork函数创建的新进程是原进程的子进程,而调用fork函数的进程是fork函数创建出来的新进程的父进程。也就是说,通过fork函数创建的新进程与原进程是父子关系,fork就相当于一个凭证,有fork,就有父子关系。
我们可以通过两个函数来做实验:
getpid() 用于获取调用getpid这个函数的进程的pid;
getppid() 用于获取调用getppid这个函数的进程的父进程的pid。
以上这段代码,我在父进程执行的代码段,加一个sleep(1),这是因为,整个程序运行的时间太短,当子进程运行getppid时,父进程可能已经结束从而导致一些意料之外的结果,好在有sleep()函数帮我们完成了测试:
可以看到,父进程在子进程结束之后再结束,使得子进程获取了其父进程的pid,哦耶。
既然刚刚说到,父进程结束了,而子进程并未结束,会有意料之外的事,这时会发生什么呢?
来看:
此时我让子进程进入死循环,并且放入后台运行,从而使得我们可以一直获取他们的pid,让父进程直接结束。
得到如下结果:
可以看到,新进程的父进程pid变成了1,那pid为1的进程又是何方神圣呢?
我们通过ps -A命令来查看:
现在我们知道了,当父进程结束了,儿子进程未结束时,子进程就变成了所谓的孤儿进程。该就交由init进程管理,init进程是一个守护进程,因为init这个进程管理了很多孤儿进程,所以也称之为进程的孤儿院。
二、数据共享
我们现在通过一段代码研究一下父子进程的是否存在数据共享。
我们现在简单把数据分成三种:堆区数据、栈区数据、全局数据。所以我现在有三个变量,同时,我让子进程改变这三个变量的值。让父进程沉睡两秒钟以确保子进程运行结束。
结果如下:
可以看到,其值发生了改变,这也说明,附子进程的堆区数据、栈区数据、全局数据是不共享的。
那子进程能和父进程共享文件吗?我们看看以下代码:
我先open一个我创建好的在同一目录下的a.txt文件,a.txt文件中我写了“Hello World!”
让父子进程一起一个字节一个字节的读文件里字符,每读一次sleep一秒钟。
结果如下:
这是什么呢,这就是说,并不是一个进程操作一个文件时,另一个进程就不能操作,而且,父子进程可以同时操作同一个文件。
也就是,在父子进程中,文件描述符以及文件偏移量,都是共享的!
为什么文件就能共享了呢,在linux源码里,每个进程都有一个PCB(进程控制块)结构体,每个PCB里,存了一个结构体指针指向一个我们理解为文件描述符的结构体struct file,而这个结构体里,才存了文件的id,从什么地方开始写,模式等等。值得注意的事,这个结构体里有一个指针才是指向真正的文件的。