fork()详解

<一>: fork()函数用来创建新的进程,它的特点是调用一次返回两次( 在原来的进程中返回新进程的 PID(新进程的 PID 肯定不等于 0), 在新进程中返回为 0.)

函数原型:pid_t fork(void);

pid_t getpid(); 获取当前进程的 pid 值。
pid_t getppid(); 获取当前进程的父进程 pid 值。
 

fork

   图一

如图一所示 :我们将A 进程, 也就是调用 fork 的进程称之为父进程, 而新的进程(B 进程)称之为子进程。

<二>:fork 的特性: fork 调用生成的新进程与其父进程谁先执行不一定。

<三>:fork的执行过程:

       (1)申请PID

       (2)申请PCB结构

       (3)复制父进程的PCB

       (4)将子进程的运行状态设置为不可执行的

       (5)将子进程中的某些属性清零,某些保留,某些修改

       (6)复制父进程的页(用到了写时拷贝技术)

这里所用到的写时拷贝技术指的是父子进程在初始阶段共享所有的数据(全局、 栈区、 堆区、 代码), 内核会将所有的区域设置为只读。 当父子进程中任意一个进程试图修改其中的数据时, 内核才会将要修改的数据所在的区域(页) 拷贝一份。

写时拷贝技术针对的是: fork 之后, 子进程往往会替换成新的程序, 所以在 fork 的时候就不需要将父进程完全拷贝出来, 当替换新程序时, 直接给子进程重新分配空间即可。
 

<四>:父子进程建数据共享问题:.data   .bss   .text   .heap的数据都不共享 ,但是父子进程之间共享 fork 之前打开的文件描述符, 并且父子进程共用文件读写偏移量。原理如图二所示:

图二   

                        图二

所以, 在执行逻辑上, fork 之前打开的文件, 要 close 两次!!


<五>在调用fork()执行后,可能会产生孤儿进程和僵尸进程,让我们一起看看到底什么是孤儿进程和僵尸进城以及怎么解决他们。

孤儿进程: 父进程结束, 子进程依旧存在。 那么子进程就被称为孤儿进程。 系统会将所有的孤儿进程挂载到 init 下。 init 进程的 pid = 1

僵尸进程:僵死进程: 1,进程结束, 但是 PCB 没释放,2,子进程结束, 父进程未结束, 并且父进程未获取子进程的退出状态

处理僵尸进程方法:
1、 结束其父进程。
2、 父进程获取子进程的退出状态: 在父进程中调用wait()函数,但是wait 函数会阻塞运行, 直到第一个子进程退出。

3、在子进程结束时,子进程给父进程发一个信号(告知父进程我已经结束了)父进程接收到信号后在对子进程做处理

猜你喜欢

转载自blog.csdn.net/weixin_41537785/article/details/81157031