Linux-vfork与fork简单对比分析 太过爱你忘了你带给我的痛 2022-06-04 04:16 176阅读 0赞 \#\#\#\#**fork相关问题:** \#\#\#\#\#**一、fork基础了解** \#\#\#\#\#fork作用为创建一个子进程,在使用了fork命令后,内核会分配新的内存块和数据结构给子进程,并且将父进程的部分数据结构内容拷贝到子进程,最后再将子进程添加到系统进程列表中,添加完成后fork返回,开始调度。 > **头文件**:\#include < unistd.h > > **函数原型**:pid\_t fork( ) > \*\*返回值:\*\*返回值大于0则当前进程为父进程,等于0代表为子进程,小于零代表创建子进程失败。 \#\#\#\#\#通过一个例子来了解: 1 #include <stdio.h> 2 #include <unistd.h> 3 4 5 int main() 6 { 7 int tmp = 5; 8 pid_t res = fork(); 9 if(res < 0){ 10 //fork失败 11 perror("fork"); 12 }else if(res == 0){ 13 //该进程为子进程 14 printf("im child[%d],fasther is %d,tmp is %d.\n",getpid(),getppid(),tmp++); 15 }else{ 16 //该进程为父进程 17 printf("im father[%d],tmp is %d.\n",getpid(),tmp++); 18 } 19 printf("tmp = %d\n",tmp); 20 return 0; 21 } -------------------- \#\#\#\#\#运行结果: 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过程中写时拷贝:** ![这里写图片描述][format_png] ![这里写图片描述][format_png 1] \#\#\#\#\#这下就不难看出,父子进程数据段和代码段开始时是共享一块对应的内存,当一方尝试写入时,便产生了写时拷贝。\*\*需要注意的是:fork之前,父进程独立执行,fork之后,父子两个执行流分别执行,至于谁先执行,由调度器决定。\*\*可通过下面例子很明显的看出是从fork之后才分别执行。 1 #include <stdio.h> 2 #include <unistd.h> 3 4 5 int main() 6 { 7 int tmp = 5; 8 printf("There is fork before\n"); 9 pid_t res = fork(); 10 if(res < 0){ 11 //fork失败 12 perror("fork"); 13 }else if(res == 0){ 14 //该进程为子进程 15 printf("im child[%d],tmp is %d.\n",getpid(),tmp++); 16 }else{ 17 //该进程为父进程 18 printf("im father[%d],tmp is %d.\n",getpid(),tmp++); 19 } 20 printf("tmp = %d\n",tmp); 21 return 0; 22 } ~ \#\#\#\#\#输出结果: \#\#\#\#\#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 < unistd.h > > **函数原型**:pid\_t vfork( ) > \*\*返回值:\*\*返回值大于0则当前进程为父进程,等于0代表为子进程,小于零代表创建子进程失败。 -------------------- \#\#\#\#\#通过一个例子来了解: 1 #include <stdio.h> 2 #include <unistd.h> 3 4 int tmp = 3; 5 6 int main() 7 { 8 pid_t res = vfork(); 9 if(res < 0){ 10 perror("vfork"); 11 _exit(1); 12 }else if(res == 0){ 13 tmp = 10; 14 printf("child res = %d\n",tmp); 15 _exit(0); 16 }else{ 17 printf("father res = %d\n",tmp); 18 } 19 20 return 0; 21 } \#\#\#\#\#**输出结果:** \#\#\#\#\#child res = 10 \#\#\#\#\#father res = 10 \#\#\#\#\#结果分析:正如上面所说的,子进程直接公用父进程的页表,改变子进程的数据也会影响到父进程。 ![这里写图片描述][format_png 2] -------------------- \#\#\#\#\#**<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先子进程,后父进程; \#\#\#\#\#二、对父进程页表的操作不同:fork()会复制父进程的页表,而vfork()不会复制,直接让子进程共用父进程的页表; [format_png]: /images/20220604/31ae1e43f2224a4cb20d707ff3206b7e.png [format_png 1]: /images/20220604/eba332764d9242e3be82fc7b20ddeff3.png [format_png 2]: /images/20220604/e4613e2dace346c6a600af0641e30ac2.png
相关 Spring Boot与Java配置对比分析 Spring Boot和Java配置在现代软件开发中都是重要的工具,它们分别代表了两种不同的设计思路。以下是两者的主要对比: 1. **简化启动过程**:Spring Boo Myth丶恋晨/ 2024年09月11日 20:57/ 0 赞/ 74 阅读
相关 PaddlePaddle与TensorFlow的详细对比分析 > 本文主要从框架概览、系统架构、编程模型、分布式架构、框架对比这五大方面比较TensorFlow和PaddlePaddle框架。作为国际两大搜索引擎研发的深度学习框架,使用侧 ゝ一世哀愁。/ 2023年07月09日 10:26/ 0 赞/ 196 阅读
相关 PostgreSQL与MySQL 分析对比 http://www.pgsql.tech/article\_101\_10000079 概述 在几个流行的数据库中,我首先接触到的是MySQL,随着工作发展,接触到越 逃离我推掉我的手/ 2022年11月18日 02:29/ 0 赞/ 220 阅读
相关 ptmalloc、tcmalloc与jemalloc对比分析 最近晚上看到了这篇文章,这里转发一下,学习记录。 [https://www.cyningsun.com/07-07-2018/memory-allocator-cont 浅浅的花香味﹌/ 2022年08月10日 12:57/ 0 赞/ 254 阅读
相关 Heartbeat 与Corosync对比分析 引言: 在高可用系统中,系统服务可用性的监控是必不可少的一项基础组件。而目前流行的是Heartbeat和corosync,对于这两者各有什么优缺点呢? 共同点: 旧城等待,/ 2022年08月10日 00:36/ 0 赞/ 219 阅读
相关 OC与Java之间的简单对比 Cocoa是什么,Cocoa是使用OC语言编写的工具包,里面有大量的类库、结构体,其实就相当于[java][]中的标准API、C++中的标准库。OC中没有命名空间 我不是女神ヾ/ 2022年07月16日 12:20/ 0 赞/ 159 阅读
相关 fork源码概要分析 fork属于系统调用,首先从用户态切换到内核态,这个过程前面已经说过了,到了内核态之后就是调用sys\_fork(),然后调用do\_fork(): asmlinka 怼烎@/ 2022年06月13日 14:39/ 0 赞/ 141 阅读
相关 Linux-vfork与fork简单对比分析 \\\\fork相关问题: \\\\\一、fork基础了解 \\\\\fork作用为创建一个子进程,在使用了fork命令后,内核会分配新的内存块和数据结构给子进程,并且 太过爱你忘了你带给我的痛/ 2022年06月04日 04:16/ 0 赞/ 177 阅读
相关 持久化框架的分析与对比 Hibernate > Hibernate:Hibernate是当前最流行的ORM框架之一,对JDBC提供了较为完整的封装。Hibernate的O/R Mapping实现 一时失言乱红尘/ 2022年05月22日 00:44/ 0 赞/ 224 阅读
还没有评论,来说两句吧...