fork,vfork,clone都是linux的系统调用,用来创建子进程的(确切说vfork创造出来的是线程)。

先介绍下进程必须的4要点:

a.要有一段程序供该进程运行,就像一场戏剧要有一个剧本一样。该程序是可以被多个进程共享的,多场戏剧用一个剧本一样。

b.有起码的私有财产,就是进程专用的系统堆栈空间。

c.有“户口”,既操作系统所说的进程控制块,在linux中具体实现是task_struct

d.有独立的存储空间。

当一个进程缺少d条件时候,我们称其为线程。

1.fork 创造的子进程复制了父亲进程的资源,包括内存的内容task_struct内容(2个进程的pid不同)。这里是资源的复制不是指针的复制。下面的例子可以看出

[root@liumengli program]# cat testFork.c

include”stdio.h”

int main() {
int count = 1;
int child;

    if(!(child = fork())) { //开始创建子进程printf("This is son, his count is: %d. and his pid is: %d\n", ++count, getpid());//子进程的内容} else {printf("This is father, his count is: %d, his pid is: %d\n", count, getpid());}

}
[root@liumengli program]# gcc testFork.c -o testFork
[root@liumengli program]# ./testFork
This is son, his count is: 2. and his pid is: 3019
This is father, his count is: 1, his pid is: 3018
[root@liumengli program]#
从代码里面可以看出2者的pid不同,内存资源count是值得复制,子进程改变了count的值,而父进程中的count没有被改变。有人认为这样大批量的复制会导致执行效率过低。其实在复制过程中,子进程复制了父进程的task_struct,系统堆栈空间和页面表,这意味着上面的程序,我们没有执行count++前,其实子进程和父进程的count指向的是同一块内存。而当子进程改变了父进程的变量时候,会通过copy_on_write的手段为所涉及的页面建立一个新的副本。所以当我们执行++count后,这时候子进程才新建了一个页面复制原来页面的内容,基本资源的复制是必须的,而且是高效的。整体看上去就像是父进程的独立存储空间也复制了一遍。

其次,我们看到子进程和父进程直接没有互相干扰,明显2者资源都独立了。我们看下面程序

[root@liumengli program]# cat testFork.c

include”stdio.h”

int main() {
int count = 1;
int child;

    if(!(child = fork())) {int i;for(i = 0; i < 200; i++) {printf("This is son, his count is: %d. and his pid is: %d\n", i, getpid());}} else {printf("This is father, his count is: %d, his pid is: %d\n", count, getpid());}

}
[root@liumengli program]# gcc testFork.c -o testFork
[root@liumengli program]# ./testFork

This is son, his count is: 46. and his pid is: 4092
This is son, his count is: 47. and his pid is: 4092
This is son, his count is: 48. and his pid is: 4092
This is son, his count is: 49. and his pid is: 4092
This is son, his count is: 50. and his pid is: 4092
This is father, his count is: 1, his pid is: 4091
[root@liumengli program]# This is son, his count is: 51. and his pid is: 4092
This is son, his count is: 52. and his pid is: 4092

(运气很衰,非要200多个才有效果,郁闷)从结果可以看出父子2个进程是同步运行的。这和下面的vfork有区别。

2.vfork创建出来的不是真正意义上的进程,而是一个线程,因为它缺少了我们上面提到的进程的四要素的第4项,独立的内存资源,看下面的程序

[root@liumengli program]# cat testVfork.c

include “stdio.h”

int main() {
int count = 1;
int child;

    printf("Before create son, the father's count is:%d\n", count);if(!(child = vfork())) {printf("This is son, his pid is: %d and the count is: %d\n", getpid(), ++count);exit(1);} else {printf("After son, This is father, his pid is: %d and the count is: %d, and the child is: %d\n", getpid(), count, child);}

}
[root@liumengli program]# gcc testVfork.c -o testVfork
[root@liumengli program]# ./testVfork
Before create son, the father’s count is:1
This is son, his pid is: 4185 and the count is: 2
After son, This is father, his pid is: 4184 and the count is: 2, and the child is: 4185
[root@liumengli program]#
从运行结果可以看到vfork创建出的子进程(线程)共享了父进程的count变量,这一次是指针复制,2者的指针指向了同一个内存,所以子进程修改了count变量,父进程的 count变量同样受到了影响。另外由vfork创造出来的子进程还会导致父进程挂起,除非子进程exit或者execve才会唤起父进程,看下面程序:

[root@liumengli program]# cat testVfork.c

include “stdio.h”

int main() {
int count = 1;
int child;

    printf("Before create son, the father's count is:%d\n", count);if(!(child = vfork())) {int i;for(i = 0; i < 100; i++) {printf("This is son, The i is: %d\n", i);if(i == 70)exit(1);}printf("This is son, his pid is: %d and the count is: %d\n", getpid(), ++count);exit(1);} else {printf("After son, This is father, his pid is: %d and the count is: %d, and the child is: %d\n", getpid(), count, child);}

}
[root@liumengli program]# gcc testVfork.c -o testVfork
[root@liumengli program]# ./testVfork

This is son, The i is: 68
This is son, The i is: 69
This is son, The i is: 70
After son, This is father, his pid is: 4433 and the count is: 1, and the child is: 4434
[root@liumengli program]#
从这里就可以看到父进程总是等子进程执行完毕后才开始继续执行。

3.clone函数功能强大,带了众多参数,因此由他创建的进程要比前面2种方法要复杂。clone可以让你有选择性的继承父进程的资源,你可以选择想vfork一样和父进程共享一个虚存空间,从而使创造的是线程,你也可以不和父进程共享,你甚至可以选择创造出来的进程和父进程不再是父子关系,而是兄弟关系。先有必要说下这个函数的结构

int clone(int (fn)(void ), void *child_stack, int flags, void *arg);

这里fn是函数指针,我们知道进程的4要素,这个就是指向程序的指针,就是所谓的“剧本”, child_stack明显是为子进程分配系统堆栈空间(在linux下系统堆栈空间是2页面,就是8K的内存,其中在这块内存中,低地址上放入了值,这个值就是进程控制块task_struct的值),flags就是标志用来描述你需要从父进程继承那些资源, 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线程标准,子进程与父进程共享相同的线程群

下面的例子是创建一个线程(子进程共享了父进程虚存空间,没有自己独立的虚存空间不能称其为进程)。父进程被挂起当子线程释放虚存资源后再继续执行。

[root@liumengli program]# cat test_clone.c

include “stdio.h”

include “sched.h”

include “signal.h”

define FIBER_STACK 8192

int a;
void * stack;
int do_something(){
printf(“This is son, the pid is:%d, the a is: %d\n”, getpid(), ++a);
free(stack); //这里我也不清楚,如果这里不释放,不知道子线程死亡后,该内存是否会释放,知情者可以告诉下,谢谢
exit(1);
}
int main() {
void * stack;
a = 1;
stack = malloc(FIBER_STACK);//为子进程申请系统堆栈
if(!stack) {
printf(“The stack failed\n”);
exit(0);
}

    printf("creating son thread!!!\n");clone(&do_something, (char *)stack + FIBER_STACK, CLONE_VM|CLONE_VFORK, 0);//创建子线程printf("This is father, my pid is: %d, the a is: %d\n", getpid(), a);exit(1);

}
[root@liumengli program]# gcc test_clone.c -o test_clone
[root@liumengli program]# ./test_clone
creating son thread!!!
This is son, the pid is:7326, the a is: 2
This is father, my pid is: 7325, the a is: 2
[root@liumengli program]#

读者可以试试其它的资源继承方式。

linux下 fork(),vfork(),clone()的用法及区别相关推荐

  1. 从一道面试题谈linux下fork的运行机制

    http://kb.cnblogs.com/page/76622/ 今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #i ...

  2. 机制 linux_从一道面试题谈linux下fork的运行机制

    今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...

  3. LINUX下FORK的运行机制详细解析

    摘要:由于fork函数运行机制的复杂性,造就了当两个fork并排时,问题就变得很复杂.解这个题的关键,一是要对linux下进程的机制有一定认识,二是抓住上文提到的几个关于fork的关键点. 今天一位朋 ...

  4. linux资源异常无法fork,linux 下 fork 后的文件资源处理问题

    我们都知道 linux 下 fork 一个子进程出来,他能够继承父进程的文件资源,网络资源等,也从父进程那里拷贝了代码段,数据段,缓冲区等等到自己这里有了新的一份,那么,如果父子进程对于打开的文件资源 ...

  5. Linux下 ls 命令的高级用法8例

    Linux下 ls 命令的高级用法8例 在Linux下,ls这个命令大家肯定太熟悉了,良许相信只要是Linux工程师,每天都会离不开这个命令,而且一天会使用个几百次.但是,除了 ls -l 以外,你还 ...

  6. linux命令grep和find怎么用,Linux下find和grep常用命令及区别介绍

    在使用linux时,经常需要进行文件查找.其中查找的命令主要有find和grep.两个命令是有区别的. 区别: (1)find命令是根据文件的属性进行查找,如文件名,文件大小,所有者,所属组,是否为空 ...

  7. Linux下useradd命令与adduser命令的区别(adduser更适合初级使用者,useradd比较适合有些高阶经验的使用者)

    文章目录 Linux下useradd命令与adduser命令的区别 man useradd man adduser Linux下useradd命令与adduser命令的区别 Linux下创建用户时会用 ...

  8. Linux下fork()函数

    Linux下的fork()函数是系统调用不是C语言内置的库函数,这里mark一下笔试面试中常出现的fork()试题. 程序一: #include "stdio.h" #includ ...

  9. 进程间通信管道进阶篇:linux下dup/dup2函数的用法

    由于利用管道实现进程间通信,是通过创建两个文件描述符,但是描述符的初始化是通过随机的,就是从可用的文件描述符中取出,并将可用的文件描述符与file对象相关联,如果我们需要将管道的两头与其他的流相关时, ...

  10. 8 个 Linux 下 ls 命令的高级用法!个个惊艳!

    作者 | 良许 责编 | 胡巍巍 在Linux下,ls这个命令大家肯定太熟悉了,笔者相信只要是Linux工程师,每天都会离不开这个命令,而且一天会使用个几百次. 但是,除了ls -l以外,你还知ls的 ...

最新文章

  1. AI都会写灵魂Rap了?Transformer跨界说唱,节奏、流畅度都不在话下
  2. latex不能识别eps图片
  3. pam mysql编译安装_pam_mysql编译过程排错
  4. 【iOS-cocos2d-X 游戏开发之十一】使用New CCSprite() CCUserDefault要注意!
  5. php重置指针,PHP数组指针函数 current,end,next,prev,reset,each
  6. 关于Jboss/Tomcat/Jetty的JNDI定义123
  7. html盒子模型子元素怎么水平占满父元素_CSS3——弹性盒模型-flex——父级属性...
  8. 单链表的实现【数据结构】
  9. freemaker转word xml注意事项
  10. 【报告分享】2021年中国人工智能产业研究报告:数字经济时代的产业升级探索.pdf(附下载链接)...
  11. html 5 新增标签及简介
  12. 主键和外键举例_数据库-主键和外键及其约束
  13. 嵌入式软件工程师岗位笔试、面试题(1)
  14. 【ML经典书籍系列1】解读PRML
  15. ISO 9001质量管理体系标准概述
  16. Shell脚本实现判断一个数是否为质数
  17. 猜数游戏(实现) 后附源码
  18. 基于javaagent-ByteBuddy监控方法执行耗时
  19. CRMEB商城直播功能-微信小程序直播
  20. 阿里AI天池大赛-天猫复购预测-基于XGBoost模型预测

热门文章

  1. linux 修改默认语言
  2. 全媒体平台可以适度超前
  3. 【数据结构】顺序存储结构
  4. Java——static修饰符 枚举
  5. react打包后图片丢失_给 React 组件自动加上 react-hot-loader
  6. Samba和用户组综合练习
  7. springboot 导出文件_开发阶段,将SpringBoot应用快速部署到K8S - 程序员欣宸
  8. linux 低功耗模式,stm32的低功耗模式:
  9. 广义pareto分布_Generalized Pareto Distribution (GPD)
  10. kaggle房价预测特征意思_未来销量预测——Kaggle基础方案(三):特征工程及线下验证划分...