一、关于fork()和exec系列区别的文字,很浅显易懂:
1、fork()
一个程序一调用fork函数,系统就为一个新的进程准备了前述三个段,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。而如果两个进程要共享什么数据的话,就要使用另一套函数(shmget,shmat,shmdt等)来操作。现在,已经是两个进程了,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零,这样,对于程序,只要判断fork函数的返回值,就知道自己是处于父进程还是子进程中。
事实上,目前大多数的unix系统在实现上并没有作真正的copy。一般的,CPU都是以“页”为单位分配空间的,象INTEL的CPU,其一页在通常情况下是4K字节大小,而无论是数据段还是堆栈段都是由许多“页”构成的,fork函数复制这两个段,只是“逻辑”上的,并非“物理”上的,也就是说,实际执行fork时,物理空间上两个进程的数据段和堆栈段都还是共享着的,当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,系统就将有区别的“页”从物理上也分开。系统在空间上的开销就可以达到最小。
2、对于exec系列函数
一个进程一旦调用exec类函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。不过exec类函数中有的还允许继承环境变量之类的信息,这个通过exec系列函数中的一部分函数的参数可以得到。
二、关于fork()和vfork()系列区别
vfork与fork主要有三点区别:
(1) fork():子进程拷贝父进程的数据段,堆栈段
vfork():子进程与父进程共享数据段
(2) fork()父子进程的执行次序不确定vfork 保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的,在它调用 exec或 exit 之后父进程才可能被调度运行。
(3) vfork()保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
1)先用fork()进行试验
#include <unistd.h> #include <stdio.h> int main(void) { pid_t pid; int count=0; pid=fork(); count++; printf("count= %d\n",count); return 0; }
分析:
通过上面fork()的说明,这个程序的输出应该是:
./test
count= 1
count= 1
2)而将fork()换成vfork()呢,程序如下
#include <unistd.h> #include <stdio.h> int main(void) { pid_t pid; int count=0; pid=vfork(); count++; printf("count= %d\n",count); return 0; }
执行结果:
./test
count= 1
count= 1
Segmentation fault (core dumped)
分析:
通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢,答案是:
vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.
3)做最后的修改,在子进程执行时,调用_exit(),程序如下:
#include <unistd.h> #include <stdio.h> #include <sys/types.h> int main(void) { pid_t pid; int count=0; pid=vfork(); if(pid==0) { count++; _exit(0); } else { count++; } printf("count= %d\n",count); return 0; }
执行结果:
./test
count= 2
分析:如果子进程中如果没有调用_exit(0),则父进程不可能被执行,在子进程调用exec(),exit()之后父进程才可能被调用.
所以加上_exit(0),使子进程退出,父进程执行.
这样 else 后的语句就会被父进程执行,又因在子进程调用 exec 或 exit 之前与父进程数据是共享的,
所以子进程把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count 变成了 2.
三、那么什么时候要用vfork() ,而不用fork()呢:
(1)vfork()共享父进程数据段,比fork()的COW节省了开销:这样的好处是在子进程被创建后仅仅是为了调用exec执行另一个程序时,因为它就不会对父进程的地址空间有任何引用,所以对地址空间的复制是多余的,通过vfork可以减少不必要的开销。
(2)vfork()保证先“子”后“父”执行:vfork创建子进程后,保证子进程先运行,在它调用exec或exit后父进程才可能调度运行(再次之前父进程一直阻塞)。而fork的父子进程运行顺序是不定的,它取决于内核的调度算法。
参考文献:
http://linux.chinaitlab.com/c/831529.html
http://linux.chinaitlab.com/c/831529_2.html
http://wenku.baidu.com/link?url=83YXzTr6TKlTw_kfnKzgZQ-jjLV2wFYxU7ZONaFHbhZ6_xxBBuR8qgG0UUcFC2GPvO0wClASwJY8V1LctSTjJwFjBGXN1ODQ6dmdmrNaPgS
神奇的vfork: http://hi.baidu.com/_kouu/item/93af230d0a22bc354ac4a3d9
相关推荐
在Linux操作系统中,`vfork()` 和 `fork()` 是两个重要的进程创建函数,它们用于创建新的进程。这两个函数都是C语言标准库中的系统调用,主要用于实现程序的并发执行,从而提升系统的多任务处理能力。然而,它们在...
在Linux操作系统中,`fork()`、`vfork()` 和 `clone()` 都是用于创建新进程的函数,但它们在实现机制和使用场景上存在显著差异。 1. **fork()** `fork()` 是最传统的进程创建方法。它创建一个与父进程完全独立的新...
vfork创建的子进程与父进程共享地址空间,直到子进程调用exec或exit为止。这意味着子进程可以立即开始执行,无需等待父进程复制内存,从而提高效率。但是,这也带来了一些限制,如父进程必须暂停执行,直到子进程...
- **资源共享**:由于`vfork`不立即复制资源,因此在新进程执行`exec`或返回前,新旧进程会共享某些资源(如内存)。这可能导致竞态条件。 - **应用场景**:`fork`适用于大多数场景;`vfork`主要用于创建临时进程...
本文将深入探讨Linux中的核心进程函数——`fork()`,以及它在创建新进程时的作用。 `fork()`是Linux系统调用中最基本的一个,它的主要功能是创建一个新的进程。当一个进程调用`fork()`时,系统会在当前进程的基础上...
### Linux 内核 do_fork 函数源代码浅析 #### 一、引言 在 Linux 内核中,进程的创建是一项基本且重要的...对于想要深入了解 Linux 内核进程管理和并发控制机制的人来说,掌握 do_fork 函数的工作原理是非常重要的。
进程间的交互和控制是通过一系列特定的系统调用来实现的,其中`fork()`、`vfork()`和`execX()`(包括`execl`, `execle`, `execv`, `execve`, `execlp`, 和 `execvp`)是非常重要的进程控制函数。下面我们将深入解析...
2. **`vfork()`** 与`fork()`类似,但它是创建一个与父进程共享地址空间的子进程,直到子进程调用`exec()`或退出。这允许子进程快速启动新的程序,而不必复制所有父进程的内存。 3. **`exec()`** 系统调用用于替换...
在Linux操作系统中,`fork()`函数是一个非常关键的系统调用,它被用来创建一个新的进程——也就是我们常说的子进程。这个过程被称为进程复制,因为子进程会继承父进程的大部分属性,包括打开的文件、内存空间、信号...
Linux操作系统中的`fork`和`vfork`都是用于创建新进程的系统调用,它们都是在父进程中创建一个与父进程几乎完全一样的子进程。然而,`vfork`和`fork`之间存在着一些显著的区别。 1. **fork基础了解**: `fork`函数...
vfork()函数与fork()函数类似,但它不允许子进程执行exec()函数,直到父进程调用wait()函数或者exit()函数。clone()函数则可以创建一个新的进程,并且可以指定新的虚拟地址空间和资源。 4. 进程创建的大致流程 ...
2. vfork()函数:类似于fork(),但子进程共享父进程的地址空间,直到调用exec()系列函数。 3. clone()函数:更底层的创建进程方法,可以自定义进程间的共享资源。 三、进程通信 1. 管道(Pipe):半双工通信,用于...
在Linux系统编程中,`fork()`, `exit()` 和 `exec()` 这三个系统调用是构建多进程程序的关键组成部分。它们允许程序创建新的进程、结束当前进程以及替换当前进程的执行上下文,从而实现复杂的功能和服务。 ### `...
实验一的目的是深入理解Linux操作系统中的进程管理,包括如何创建、管理和控制进程。在这个实验中,涉及了几个关键的系统调用和概念: 1. **fork()**:这是创建新进程的主要方法。当调用fork()时,父进程创建一个与...
在 Linux 中,进程创建主要通过三种方式实现:`fork()`、`vfork()` 和 `clone()`。这些系统调用不仅在日常编程中非常常见,也是深入理解 Linux 内核工作原理的关键所在。 #### 二、系统调用与内核函数对应关系 ...
- `vfork()`类似于`fork()`,但子进程会与父进程共享地址空间,直到子进程调用`exec()`或`_exit()`。 - `exit()`和 `_exit()`用于进程退出,但`exit()`会执行清理工作,如执行析构函数和释放文件描述符。 - `wait...
在Linux操作系统中,`vfork()`和`fork()`都是创建新进程的系统调用,但它们之间存在着显著的差异。本篇文章将深入探讨`vfork()`的原理、特点以及与`fork()`的区别,并通过C语言的源代码示例进行解析。 `vfork()`是...
一、描述进程——PCB ·进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合 ·我们称为PCB,Linux操作系统下的PCB是:task struct 2、task_struct——PCB的一种 ·在Linux中描述进程的结构体...
`vfork()` 是一个轻量级的进程创建函数,它会创建一个新的进程,但新进程与父进程共享同一地址空间,直到新进程调用`exec`系列函数(如`execl()`)或退出。`vfork()` 主要用于快速创建新进程,然后使用`execl()`替换...