热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

浅谈Linuxvfork与fork简单对比分析

本文分享了Linux vfork与fork简单对比分析,分享给大家,具体如下: fork相关问题: 一、fork基础了解 fork

本文分享了Linux vfork与fork简单对比分析,分享给大家,具体如下:

fork相关问题:

一、fork基础了解

fork作用为创建一个子进程,在使用了fork命令后,内核会分配新的内存块和数据结构给子进程,并且将父进程的部分数据结构内容拷贝到子进程,最后再将子进程添加到系统进程列表中,添加完成后fork返回,开始调度。

头文件:#include

函数原型:pid_t fork( )

返回值:返回值大于0则当前进程为父进程,等于0代表为子进程,小于零代表创建子进程失败。

通过一个例子来了解:

  #include 
  #include 
  
    
  int main()
  {
    int tmp = 5;
    pid_t res = fork();
    if(res <0){
     //fork失败
     perror("fork");
   }else if(res == 0){
     //该进程为子进程
     printf("im child[%d],fasther is %d,tmp is %d.\n",getpid(),getppid(),tmp++);
   }else{
     //该进程为父进程
     printf("im father[%d],tmp is %d.\n",getpid(),tmp++);
   }
   printf("tmp = %d\n",tmp);
   return 0;
 }     

运行结果:

im father[3128],tmp is 5.
tmp = 6
im child[3129],fasther is 1,tmp is 5.
tmp = 6

相关问题小结:

通过结果很明显的能看出本次调用中,先执行父进程,对应pid为3128,在父进程中tmp++,所以输出为6;关键问题在于子进程,有两个关键点。

①为什么结果中子进程父亲pid为1:通过输出我们能看出父进程先执行完成后才执行的子进程,也就是说当子进程执行时父进程已结束,此时该子进程相当于一个孤儿进程,被pid为1也就是Init进程所管理,所以子进程的ppid为1;

②为什么子进程最后输出tmp值还为6: fork进程采用的是写时拷贝,父子进程一开始共享一片内存区域,但是只有有一方要对数据进行修改,则再开辟一块空间,防止相互修改影响。所以在上述代码中,虽说是一个tmp,其实内存中各自保留了一份值。

二、关于fork过程中写时拷贝:

这里写图片描述 

这里写图片描述

这下就不难看出,父子进程数据段和代码段开始时是共享一块对应的内存,当一方尝试写入时,便产生了写时拷贝。需要注意的是:fork之前,父进程独立执行,fork之后,父子两个执行流分别执行,至于谁先执行,由调度器决定。可通过下面例子很明显的看出是从fork之后才分别执行。

  #include 
  #include 
  
  
  int main()
  {
    int tmp = 5;
    printf("There is fork before\n");
    pid_t res = fork();
   if(res <0){
     //fork失败
     perror("fork");
   }else if(res == 0){
     //该进程为子进程
     printf("im child[%d],tmp is %d.\n",getpid(),tmp++);
   }else{
     //该进程为父进程
     printf("im father[%d],tmp is %d.\n",getpid(),tmp++);
   }
   printf("tmp = %d\n",tmp);
   return 0;
 }

输出结果:

There is fork before

im father[3625],tmp is 5.

tmp = 6

im child[3626],tmp is 5.

tmp = 6

三、fork调用失败的原因:

①系统中已经存在太多进程,无法再创建新的进程。可通过ulimit -a命令查看当前所有的资源限制。

②内存不足,由于开辟每个新的进程都要分配一个PCB,并为新进程分配资源,内存都不足也就别提还想着再创建进程了。

vfork相关问题:

一、vfork基础了解

<1>vfork创建新进程的主要目的在于用exec函数执行另外的程序,实际上,在没调用exec或_exit之前子进程与父进程共享数据段。在vfork调用中,子进程先运行,父进程挂起,直到子进程调用exec或_exit,在这以后,父子进程的执行顺序不再有限制。

头文件:#include

函数原型:pid_t vfork( )

返回值:返回值大于0则当前进程为父进程,等于0代表为子进程,小于零代表创建子进程失败。

通过一个例子来了解:

 #include 
  #include 
  
  int tmp = 3;
  
  int main()
  {
    pid_t res = vfork();
    if(res <0){
     perror("vfork");
     _exit();
   }else if(res == 0){
    tmp = 10;
 printf("child res = %d\n",tmp);
     _exit(0);
   }else{
     printf("father res = %d\n",tmp);
   }
 
   return 0;
 }

输出结果:

child res = 10

father res = 10

结果分析:正如上面所说的,子进程直接公用父进程的页表,改变子进程的数据也会影响到父进程。

这里写图片描述

<2>vfork用处:

vfork()跟fork()类似,都是创建一个子进程,这两个函数的的返回值也具有相同的含义。但是vfork()创建的子进程基本上只能做一件事,那就是立即调用_exit()函数或者exec函数族成员,调用任何其它函数(包括exit())、修改任何数据(除了保存vfork()返回值的那个变量)、执行任何其它语句(包括return)都是不应该的。更需要注意的是:调用vfork()之后,父进程会一直阻塞,直到子进程调用_exit()终止,或者调用exec函数族成员。

<3>为什么只能用_exit退出:

exit()是对_exit()的封装,它自己在调用_exit()前会做很多清理工作,其中包括刷新并关闭当前进程使用的流缓冲(比如stdio.h里面的printf等),由于vfork()的子进程完全共享了父进程地址空间,子进程里面的流也是共享的父进程的流,所以子进程里面是不能做这些事的。直接return就更不行了,子进程return以后,会从当前函数的外部调用点后面继续执行,这后面子进程可能将会执行很多语句,结果就没法预料了。在man手册中也强调了这一点,必须使用_exit退出。

fork与vfork的区别

1.vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

2.fork要拷贝父进程的进程环境;而vfork则不需要完全拷贝父进程的进程环境,在子进程没有调用exec和exit之前,子进程与父进程共享进程环境,相当于线程的概念,此时父进程阻塞等待。

为什么会有vfork呢&#63;

因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,然后将会有两种行为:

1.执行从父进程那里拷贝过来的代码段

2.调用一个exec执行一个新的代码段

当进程调用exec函数时,一个新程序替换了当前进程的正文,数据,堆和栈段。这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork。vfork并不复制父进程的进程环境,子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。

因此,如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了如何在 Windows 系统上利用 Docker 构建一个包含 NGINX、PHP、MySQL、Redis 和 Elasticsearch 的集成开发环境。通过详细的步骤说明,帮助开发者快速搭建和配置这一复杂的技术栈,提升开发效率和环境一致性。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 在Ubuntu系统中配置Python环境变量是确保项目顺利运行的关键步骤。本文介绍了如何将Windows上的Django项目迁移到Ubuntu,并解决因虚拟环境导致的模块缺失问题。通过详细的操作指南,帮助读者正确配置虚拟环境,确保所有第三方库都能被正确识别和使用。此外,还提供了一些实用的技巧,如如何检查环境变量配置是否正确,以及如何在多个虚拟环境之间切换。 ... [详细]
  • 本文提供了详细的 Filebeat 部署指南,涵盖了解压安装包、配置文件编辑以及启动服务等关键步骤。具体操作包括使用 `tar -zxvf filebeat-6.1.1-linux-x86_64.tar.gz` 解压安装包,并通过 `vi /home/elk/filebeat-6.4.2-linux/filebeat.yml` 编辑配置文件。此外,文章还介绍了最佳实践,帮助用户确保 Filebeat 的高效运行和数据传输的可靠性。 ... [详细]
  • PHP与MySQL的Web应用开发技术深入解析
    PHP与MySQL的Web应用开发技术深入解析 ... [详细]
  • 《我的世界》Java版与Windows 10版(基岩版)有何不同?
    《我的世界》Java版与Windows 10版(基岩版)有何不同? ... [详细]
  • 在64位Linux系统上编译GCC时,可能会遇到一个错误,即在构建共享库过程中,`.libs/alloc.o` 文件中的重定位 `R_X86_64_32` 无法应用于 `.rodata.str1.8` 段。这一问题通常与目标文件的地址空间限制有关,需要通过调整编译选项或修改源代码来解决。具体来说,可以尝试使用 `-fPIC` 选项以生成位置无关代码,或者检查相关对象文件的链接方式。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • Linux系统防火墙启用与端口开放详细指南及操作流程
    在Linux系统中,启用防火墙并开放特定端口是确保网络安全的重要步骤。本文详细介绍了防火墙的配置方法和操作流程,包括如何解决在使用 `service iptables save` 命令时遇到的常见问题,如命令不支持基本的LSB动作(启动、停止等)的情况。此外,还提供了多种解决方案和最佳实践,帮助用户高效地管理和维护系统安全。 ... [详细]
  • 在网络故障排查中,tcpdump 是一款强大的工具,尤其在 Linux 环境下。尽管开发环境中问题较少,但在测试或生产环境中,往往会遇到各种难以预料的异常情况。通过在问题发生的环境中启用 tcpdump 进行抓包,并重现问题,可以获取到宝贵的原始数据,为问题的诊断提供关键线索。本文将详细介绍如何使用 tcpdump 进行实战操作,帮助读者掌握这一技能。 ... [详细]
  • 在Linux系统中,针对USB输入设备(如鼠标和电容触摸屏)的动力分配后,自动创建的input节点可能导致事件处理不稳定。本文探讨了如何在Qt开发环境中,通过合理配置设备事件处理器,确保USB输入设备的稳定性和可靠性。具体实例包括使用udev规则进行设备节点的持久化管理,以及通过事件监听机制优化事件处理流程。 ... [详细]
  • 探究大数据环境下Kafka实现高性能的几个关键因素
    在大数据环境下,Kafka能够实现高性能的关键因素在于其独特的设计和优化策略。尽管Kafka的消息存储在磁盘上,这通常被认为会降低性能,但通过高效的文件管理和批量处理机制,Kafka能够在高吞吐量和低延迟之间取得平衡。此外,Kafka还利用了零拷贝技术、压缩算法和异步IO等手段,进一步提升了系统的整体性能。这些技术不仅保证了数据的可靠性和持久性,还使得Kafka成为处理大规模实时数据流的理想选择。 ... [详细]
  • 在VMware虚拟机中部署带有中文图形界面的CentOS 7 Linux系统
    本文详细介绍了在VMware虚拟机中部署带有中文图形界面的CentOS 7 Linux系统的步骤。首先,通过“文件”菜单选择“新建虚拟机”并进入自定义设置。接着,在硬盘兼容性选项中选择默认设置。为了更好地进行Linux操作系统的安装练习,建议选择稍后安装操作系统,并在虚拟机安装完成后,根据实际需求删除不必要的硬件组件。此外,本文还提供了详细的配置参数和注意事项,帮助用户顺利完成整个部署过程。 ... [详细]
  • 深入解析 Linux 内核中的 signal.c 文件:从泛读到精析
    本文将对 Linux 内核中的 `signal.c` 文件进行深入解析,从泛读到精析,全面解读其核心功能与实现机制。通过详细分析代码,探讨信号处理的内部运作,帮助读者更好地理解 Linux 内核的信号处理机制。相关学习资料已整理在 GitHub 仓库:https://github.com/GreyZhang/little_bits_of_linux。 ... [详细]
  • 在Linux系统中,通过调整内存配置可以有效提升程序运行时的性能。本文将探讨如何在Linux环境下优化内存分配,特别是针对使用Go语言开发的应用程序,提供实用的技巧和最佳实践,帮助Golang开发者提高程序的稳定性和效率。 ... [详细]
author-avatar
ayo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有