fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了“写时复制“技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。于是起初我就感到奇怪,子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢?!原来在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,如果不是因为exec,内核会给子进程的数据段、堆栈段分配相应的物理空间(至此两者有各自的进程空间,互不影响),而代码段继续共享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
在网上看到还有个细节问题就是,fork之后内核会通过将子进程放在队列的前面,以让子进程先执行,以免父进程执行导致写时复制,而后子进程执行exec系统调用,因无意义的复制而造成效率的下降。
详细情况可以看看这位仁兄的文章:十辨十析之辨一――fork()、写时复制、vfork()
最近几本关于L的书,想来通络一下。也干了近几件疯狂的事情,想想都要偷着自娱自乐一番,真是无聊到尽头了,也就是另一番风景。有些你以前一直巴巴的信仰为真的东西,偶乐改变一下,结果发现,原来不是那个理,换个道也没什么比以前差的,丫,这样,也不错。
打算写十辨十析,罗罗一大堆,写些什么呢,想来想去,还是写些基础的东西吧,希望这些基础的东西对朋友们理解其它方面能有个帮助。这个专题的思想:what ? why ? how ? 总之要从根基上讲清楚,重点在原理上了。对了图作的不精,请大家谅解。
这三个方法是大佬L用 于创建子进程的三种方法。其实理解它们,要有一个实现上的意识即:进程->虚拟地址空间->物理地址空间即真实的存储。用户进程能感知的是进程的虚拟地址 空间,而虚拟地址空间->物理地址空间则由底层的内核来帮你实现。一个进程在地址空间上的表现形式就是:正文段,数据段,堆,栈。嗯,主要就是这四个部 分,内核为其分配相应的数据结构来表示它们,其看做是进程在地址空间的实体,也可以想象为灵魂。随后内核会为这四部分分配相应的载体,即真正的物理存储, 就像灵魂要附之于身体一样,那么,这些物理存储就是进程的真正实体的,我们称之为身体。那么这三个方法有什么不同呢?
ok,现在有一个父进程P1,这是一个主体,那么它是有灵魂也就身体的哦。现在在其虚拟地址空间(有相应的数据结构表示)上有:正文段,数据段,堆,栈这四个部分,相应的,内核要为这四个部分分配各自的物理块。即:正文段块,数据段块,堆块,栈块。至于如何分配,这是内核去做的事,在此不详述。
1. 现在P1用fork()函数为进程创建一个子进程P2,内核:(1)复制P1的正文段,数据段,堆,栈这四个部分,注意是其内容相同。(2)为这四个部分分配物理块,P2的:正文段->PI的正文段的物理块,其实就是不为P2分配正文段块,让P2的正文段指向P1的正文段块,数据段->P2自己的数据段块(为其分配对应的块),堆->P2自己的堆块,栈->P2自己的栈块。如下图所示:同左到右大的方向箭头表示复制内容。

图1
2. 写时复制技术:内核只为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟究竟结构,但是不为这些段分配物理内存,它们共享父进程的物理空间,当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间。

图2
3. vfork():这个做法更加火爆,内核连子进程的虚拟地址空间结构也不创建了,直接共享了父进程的虚拟空间,当然了,这种做法就顺水推舟的共享了父进程的物理空间。

图3
通 过以上的分析,相信大家对进程有个深入的认识,它是怎么一层层体现出自己来的,进程是一个主体,那么它就有灵魂与身体,系统必须为实现它创建相应的实体, 灵魂实体与物理实体。这两者在系统中都有相应的数据结构表示,物理实体更是体现了它的物理意义。呵呵,说了这么多,其实系统之所以提供这三个方法,也都是 从实现效率上来考虑的,一般fork后要exec,所以很多父进程的数据对于子进程来说都是不需要的,后两种方法就是大佬L区别于Unix的一个主要特征,也可以说是其高明处之一吧,其创建进程特别的高效,怎么高效,通过以上的比较与分析,相信大家也能明白个五六了吧。
分享到:
相关推荐
在`fork()`成功执行后,控制权将分别返回到父进程和子进程,每个进程都会得到`fork()`调用返回值,其中父进程得到的是子进程的PID,而子进程得到的是0。 在"fork创建子进程"的实验中,你会看到如何在C语言中使用`...
fork 函数与 vfork 函数的区别在于:vfork 函数创建的子进程会在父进程的地址空间中执行,而不是在自己的地址空间中执行。这意味着,vfork 函数创建的子进程不能修改父进程的地址空间。 在使用 fork 函数时,为什么...
当父进程调用`fork()`时,操作系统会复制父进程的所有资源(如内存空间、文件描述符等)给新创建的子进程,形成一份完全独立的副本。因此,`fork()`之后,会返回两次:一次在父进程中,一次在子进程中,返回值分别是...
由于 `fork()` 在父进程中返回子进程的 PID,在子进程中返回 0,因此可以通过检查 `pid` 的值来区分父进程和子进程,并据此执行不同的代码。 #### 四、为什么子进程从fork后开始执行? 如果子进程也从 `main()` ...
- 父进程继续执行 `fork` 后的代码,而子进程从 `fork` 函数处开始执行。 2. **关键点:** - 父进程执行了所有代码,子进程仅执行 `fork` 后的代码。 - 子进程继承的是父进程 `fork` 时的环境状态,而非初始...
- 或者在`fork`后,通过`CLONE_PARENT`标志调用`clone`,使新的子进程认为指定的进程是其父进程。 ### 5. 安全与风险 尽管指定父进程能带来一定的灵活性和控制力,但也可能存在安全风险。未经授权的进程修改父进程...
`fork()`调用成功后,它会在父进程和子进程中都返回一个值,通常在父进程中返回新创建子进程的进程ID,在子进程中返回0。这样,通过检查`fork()`的返回值,我们可以区分哪个是父进程,哪个是子进程。 在描述中提到...
在创建过程中,父进程会复制自身的内存空间,包括代码、数据、堆栈等,生成一个全新的子进程。这两个进程拥有相同的初始状态,但它们各自拥有独立的进程ID(PID)。在给出的代码段中,父进程打印"parent process is ...
虽然这个例子没有涉及,但通常父进程和子进程之间可能需要进行通信,例如通过共享内存、管道、信号量等方式交换数据。在实际应用中,了解如何在父子进程间传递信息是至关重要的。 总结起来,这个程序演示了如何在...
一旦`fork()`函数执行完毕,父进程与子进程都将从`fork()`函数调用的下一行代码继续执行。 #### 四、示例程序分析 下面通过两个示例程序来进一步理解`fork()`函数的具体应用。 ##### 示例1: 简单的父子进程演示 ...
新进程拥有与父进程一样的内存空间、文件描述符、环境变量等资源,但它们各自拥有独立的进程标识符(PID)。 在提供的代码中,我们看到`fork()`被用于循环内,这将导致创建多个层级的子进程。`fork()`的返回值对于...
`fork()`调用成功时,会返回两次:一次在父进程中返回新创建子进程的PID(进程ID),一次在子进程中返回0。通过检查返回值,我们可以区分父进程和子进程,并进行不同的操作。 在服务器端,我们首先创建一个监听套接...
2. **守护进程**:通过`fork()`创建一个子进程后,父进程退出,子进程成为孤儿进程,最终由init进程接管,这样就可以创建一个脱离终端、在后台运行的守护进程。 3. **进程间通信**:通过`fork()`创建子进程后,利用...
2. **Exec()函数家族**:在使用fork创建子进程后,往往需要使用exec函数替换子进程的内存映像,加载新的程序执行。常见的有execl、execlp、execle、execv、execvp和execve等,它们用于执行指定的程序并替换当前进程...
### 子进程与父进程的关系 1. **拷贝-on-write (COW) 机制**:在`fork()`之后,子进程和父进程共享同一份物理内存页,但它们对这些页面的修改会被隔离。这是因为Linux采用了一种叫做拷贝-on-write的技术,只有当...
本文将详细解析这个主题,探讨Console应用程序、子进程与父进程之间的关系,以及它们在实际操作中的应用。 首先,我们来理解什么是Console应用程序。Console应用程序,也称为控制台应用程序,是那些在命令行界面...
`fork()`编程是系统调用的一个重要部分,它允许一个正在运行的进程(父进程)创建一个与自身几乎完全相同的副本(子进程)。这个特性使得多进程编程成为可能,是实现并发执行和并行处理的基础。 一、`fork()`函数...
2.1 返回值:在成功执行Fork后,父进程和子进程都会继续执行fork之后的语句,但fork调用会返回不同的值。在父进程中,fork返回新创建子进程的PID;而在子进程中,fork返回0。这一特性使得父子进程可以区分彼此,从而...
这个过程被称为进程复制,因为子进程会得到父进程的所有属性,包括打开的文件、环境变量、内存映射等的一个副本。然而,子进程和父进程在`fork()`之后具有独立的进程ID(PID)和系统资源,比如它们可以有不同的执行...
fork 函数的返回值在父进程和子进程中不同,在父进程中返回新创建的子进程的进程 ID,在子进程中返回 0。 fork 函数的执行过程可以分为两个阶段:第一阶段是创建新的进程,系统给新的进程分配资源,例如存储数据和...