详解linux中fork、vfork、clone函数的区别

在linux系统中,fork(),vfork()和clone函数都可以创建一个进程,但是它们的区别是什么呢???本文就这三者做一个较深入的分析!!!

1.fork()

  fork()函数的作用是创建一个新进程,由fork创建的进程称为子进程,fork函数调用一次返回两次,子进程返回值为0,父进程返回子进程的进程ID。我们知道,一个进程的地

址空间主要由代码段,数据段,堆和栈构成,那么p2就要复制相关的段到物理内存。原始的unix系统的实现的是一种傻

瓜式的进程创建,这些复制包括:

(1) 为子进程的页表分配页面,确定页表的位置;

(2)为子进程的页分配页面,确定子进程页面的位置;

(3)初始化子进程的页表;

(4)把父进程的页复制到子进程对应的页中

从图中我们可以看出除了正文段外,子进程的所有其它段都分配了物理空间,并将父进程的相关内容拷贝过来。父进程的task_struct结构中的打开文件描述符,进程组ID,

回话ID都进行复制。

下面通过简单的代码检测一下fork()函数:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys types.h="">
#include <pthread.h>
#include
#include <iostream>
using namespace std;
int main() {
  int num = 1;
  int child;
  if(!(child =fork())) {
  cout<<&num<<endl; address:="" alt="\" child="vfork()))" class="brush:java;" else="" father="" img="" include="" int="" is:="" namespace="" num="1;" num:="" pid="" pre="" son="" src="/uploadfile/Collfiles/20170421/201704210949041534.jpg" sys="" types.h="" using=""><p>测试结果:</p><p><img alt="\" src="/uploadfile/Collfiles/20170421/201704210949041535.jpg" style="width: 630px; height: 201.393px;"></p><p>从测试结果中我们可以看到,在子进程修改了num变量的值后,父进程的num的值也发生改变,说明对于子进程和父进程来说,它们操作的是同一个地方的num值,下面就是vfork的示意图:</p><p><img alt="\" src="/uploadfile/Collfiles/20170421/201704210949041536.jpg" style="width: 508px; height: 375px;"></p><p>可以看出子进程直接共享了父进程的虚拟进程空间。</p><p>3.clone()</p><p>  clone()函数是linux系统中,用来创建轻量级进程。</p><p>函数原形:</p><pre class="brush:java;">int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
下面是flags可以取的值
标志     含义
CLONE_PARENT 创建的子进程的父进程是调用者的父进程,新进程与创建它的进程成了“兄弟”而不是“父子”
CLONE_FS   子进程与父进程共享相同的文件系统,包括root、当前目录、umask
CLONE_FILES  子进程与父进程共享相同的文件描述符(file descriptor)表
CLONE_NEWNS 在新的namespace启动子进程,namespace描述了进程的文件hierarchy
CLONE_SIGHAND 子进程与父进程共享相同的信号处理(signal handler)表
CLONE_PTRACE 若父进程被trace,子进程也被trace
CLONE_VFORK  父进程被挂起,直至子进程释放虚拟内存资源
CLONE_VM   子进程与父进程运行于相同的内存空间
CLONE_PID   子进程在创建时PID与父进程一致
CLONE_THREAD Linux 2.4中增加以支持POSIX线程标准,子进程与父进程共享相同的线程群
下面的例子是创建一个线程(子进程共享了父进程虚存空间,没有自己独立的虚存空间不能称其为进程)。父进程被挂起当子线程释放虚
存资源后再继续执行。</pre>
测试代码1:
<pre class="brush:java;">#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys types.h="">
#include <pthread.h>
#include
#include <iostream>
using namespace std;
#define FIBER_STACK 8192
int a;
void * stack;
int func(void *){
 cout<<&a<<endl; a="" char="" creating="" int="" is="" is:="" my="" pid="" pre="" son="" stack="" the="" this="" void="">
结果:<p><img alt="\" src="/uploadfile/Collfiles/20170421/201704210949041537.png" style="width: 630px; height: 201.393px;"></p><p>测试代码2(做如下修改):</p><pre class="brush:java;">clone(func, (char *)stack + FIBER_STACK,CLONE_VFORK, 0);</pre>
结果:
<p><img alt="\" src="http://www.jb51.net/uploadfile/Collfiles/20170421/201704210949041538.png" style="display: block; width: 630px; height: 201.393px;"></p>
<p>很明显,在测试2中将CLONE_VM删掉之后,子进程和父进程就不会公用页表,子进程创建新的页表。从某种意义上来说,clone其实是fork和vfrok的更高层次版本,,它们的关</p>
<p>系如下(《深入理解linux内核》中描述):</p>
<p>   <strong>传统的fork()系统调用在Linux中是用clone()实现的,其中clone()的flags参数指定为sigchld信号以及所有清0的clone标志,而它的child_stack参数是父进程当前的堆栈</strong></p>
<p><strong>指针,因此,父进程和子进程暂时共享一个用户态堆栈。而vfork函数系统调用也是用clone实现的,其中clone()的参数flags指定为sigchld和CLONE_VFORK和CLONE_VM标</strong></p>
<p><strong>志,clone()的参数child_stack等于父进程当前的栈指针!!!</strong></p>
。只是有一点不明白,把int a和void * stack挪到main函数里面之后,就会出现编译错误,显示未定义a和stack,这点有些不懂,望高人指点!!!! </endl;></iostream></assert.h></pthread.h></sys></unistd.h></stdlib.h></stdio.h></pre>
</endl;></iostream></assert.h></pthread.h></sys></unistd.h></stdlib.h></stdio.h>

以上所述是小编给大家介绍的linux中fork、vfork、clone函数的区别,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Linux 中fork的执行的实例详解

    Linux 中fork的执行的实例详解 先看看一段fork的程序 int main() { pid_t pid; 语句 a; pid = fork(); 语句 b; } 1.当程序运行到 pid = fork()时,这个进程马上分裂(fork的中文意思)成两个进程,我们称为父进程和子进程,子进程是父进程的副本,副本的意思是子进程把父进程的数据空间,堆和栈都复制一遍给自己用,这要求在内存给子进程分配和父进程同样大的存储空间,这样,父,子进程拥有相同的数据,但不会共享存储空间,他们只是共享正文段.

  • C语言的fork函数在Linux中的进程操作及相关面试题讲解

    fork的意义 下图为,C 程序的存储空间布局(典型) 1.一个现有进程可以调用 fork 函数创建一个新进程. 2.fork 函数被调用一次,但返回两次, 两次返回的唯一区别是子进程的返回值是 0, 而父进程的返回值是新子进程的 PID. 3.子进程和父进程继续执行 fork 调用之后的指令. 在上图的存储空间布局中,父子进程只共享正文段,其余的都各自有独立的副本 (通常使用 copy-on-write 的策略,速度比较快). fork 的两种用法 1.父子进程同时执行不同的代码段 典型应用:

  • Linux中fork()函数实例分析

    一.fork 入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. 我们来看一个例子: /* * fork_test.c * version 1 * C

  • Linux系统中C语言编程创建函数fork()执行解析

    最近在看进程间的通信,看到了fork()函数,虽然以前用过,这次经过思考加深了理解.现总结如下: 1.函数本身 (1)头文件 #include<unistd.h> #include<sys/types.h> (2)函数原型 pid_t fork( void); (pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中) 返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID:否则,出错返回-1 (3)函数说明 一

  • 浅谈Linux环境下并发编程中C语言fork()函数的使用

    由fork创建的新进程被称为子进程(child process).fork函数被调用一次,但返回两次.子进程的返回值是0,而父进程的返回值则是新进程的进程ID.将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID.fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getpid以获得其父进程的进程ID. 使fork失败的两个主要原因是:系统中已经有了太多的进程,或者该实际用户ID的进程总数超过

  • 简单掌握Linux系统中fork()函数创建子进程的用法

    fork()函数用于从已存在的进程中创建一个新进程.新进程称为子进程,而园进程称为父进程.使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文.代码段.进程堆栈.内存信息.打开的文件描述符.符号控制设定.进程优先级.进程组号.当前工作目录.根目录.资源限制和控制终端等,而子进程所独有的只有它的进程号.资源使用和计时器等. 因为子进程几乎是父进程的完全复制,所以父子两进程会运行同一个程序.这就需要用一种方式来区分它们,并使它们照此运行,否则,

  • 使用C语言的fork()函数在Linux中创建进程的实例讲解

    在Linux中创建一个新进程的唯一方法是使用fork()函数.fork()函数是Linux中一个非常重要的函数,和以往遇到的函数有一些区别,因为fork()函数看起来执行一次却返回两个值. fork()函数用于从已存在的进程中创建一个新进程.新进程称为子进程,而园进程称为父进程.使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文.代码段.进程堆栈.内存信息.打开的文件描述符.符号控制设定.进程优先级.进程组号.当前工作目录.根目录.资源限

  • Linux中使用C语言的fork()函数创建子进程的实例教程

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己.   我们来看一个例子: #include <unistd.h> #include &

  • Linux下C语言的fork()子进程函数用法及相关问题解析

    fork fork()函数是linux下的一个系统调用,它的作用是产生一个子进程,子进程是当前进程的一个副本,它跟父进程有一样的虚存内容,但也有一些不同点. 但是,值得注意的是,父进程调用fork()后,fork()返回的是生成的子进程(如果能顺利生成的话)的ID.子进程执行的起点也是代码中fork的位置,不同的是下面这段C语言代码展示了fork()函数的使用方法: // myfork.c #include <unistd.h> #include <stdio.h> int mai

  • Linux 编程之进程fork()详解及实例

    Linux fork()详解: 在开始之前,我们先来了解一些基本的概念: 1. 程序, 没有在运行的可执行文件 进程,  运行中的程序 2. 进程调度的方法: 按时间片轮转       先来先服务      短时间优先      按优先级别 3. 进程的状态: 就绪   ->>   运行  ->> 等待          运行 ->> 就绪 //时间片完了          等待 ->> 就绪 //等待的条件完成了 查看当前系统进程的状态 ps auxf s

随机推荐