当前位置: 首页 > news >正文

linux中fork()函数的小问题

问题描述:分析下列代码,分别能产生多少a 

//  1
for(int i=0; i<3; i++){
printf("a\n");
fork();
}// 2
for(int i=0; i<3; i++){
fork();
printf("a\n");
}// 3
for(int i=0; i<3; i++){
fork();
printf("a");
}
fflush(stdout);// 4
for(int i=0; i<3; i++){
printf("a");
fork();
}

分析:

【问题1】第0次循环:此时只有p0主进程,直接输出a,然后执行fork();产生一个子进程p1;现在有一个a

        第1次循环:此时有两个进程p0,p1;都输出一个a ,共两个a;然后执行fork();分别产生p2,p3,两个子进程;目前终端输出三个a,有四个进程p0,p1,p2,p3;

        第2次循环:此时四个进程各输出一个 a ;随后产生四个进程,程序结束;终端上一共有1+2+4 = 7 个a。

【问题2】第0次循环:此时只有p0主进程,执行fork(),生成子进程p1,两个进程各自在终端输出一个a,此时终端共两个a;

        第1次循环:此时有p0,p1进程,执行fork(),生成子进程p2,p3,共四个进程,各自输出一个a,此时终端共有 2+4 = 6 个a;

        第2次循环:此时有p0,p1,p2,p3进程,执行fork(),生成四个子进程,共八个子进程,各自在终端输出8个子进程,此时共有 2+ 4+8 = 14个a;

        但是在终端上出现如下情况,原因为各进程间结束时间不一致,当主进程结束时,部分子进程还未结束,会继续向终端输出a;

 此时只要在for循环后加sleep();等待进程全结束即可得到规整的输出:

 void test2(){12     printf("[test2] 预测有 14个\n");13     for(int i=0;i<3;i++){14        fork();15         printf("[test2] : a\n");16     }17 18     sleep(1);                                                                               19 }   

 【问题3】(注:本题以及问题4涉及缓存相关知识)

        第0次循环:主进程p0执行fork()后产生子进程p1,随后执行满缓存输出,此时将a输出当进程p0、p1的缓冲区中,并不直接输出到终端(后两次循环也是一样);

        第1次循环:p0,p1执行fork()后产生p2,p3子进程,随后执行printf(),将a输出到各进程的缓冲区中,此时p0,p1,p2,p3中的缓冲区都存在两个但还未输出;

        第2次循环:同理第1次循环,会产生四个子进程,共八个进程,随后的printf()在各自的进程缓存空间中输出a,当进程结束时,标准输出会刷新缓存,将每个进程中的三个a输出到终端;程序结束后,终端上会显示 3*8 = 24个 a;

 若出现输出在命令行之后的情况,原因同问题2,各个进程结束时间不一致导致,使用sleep()就可以解决。

【4】

        第0次循环:主进程p0执行printf()后并未直接输出,而是将a输出到p0的缓存中。随后执行fork(),产生的子进程p1会复制p0的用户态地址空间;这里有个小知识点fork()采用写时复制,在随后对共享页中i++时候才真正复制p0的栈堆数据等,此时才将p0中的缓存复制一份,这是区别与问题3的;问题3是在各自缓存中加了一个a,问题4是在父进程缓存中先加了一个a,随后复制到各子进程(后两次不作过多赘述,fork()写时复制策略放在最后);此时p0,p1缓存中各有一个a;

        第1次循环:p0,p1执行printf(),将a输出到各进程的缓冲区中,缓存中各自有两个a,执行fork(),产生p2,p3,此时p0,p1,p2,p3中的缓冲区都存在两个a但还未输出;

        第2次循环:同理上次循环,会产生四个子进程,共八个进程,并且在fork()前的printf()在各自的进程缓存空间中输出a,各个进程缓存中存在3个a,当进程结束时,标准输出会刷新缓存,将每个进程中的三个a输出到终端;程序结束后,终端上会显示 3*8 = 24个 a;

 

写时复制

为了减少数据复制的开销, 优化内存管理, fork采用是写时复制(Copy-On-Write,简称COW)的策略

  1. 在fork()执行时,操作系统并不立即复制父进程的整个内存空间给子进程。操作系统使父进程和子进程暂时共享相同的物理内存页。
  2. 这些共享的页面在内存中被标记为只读。如果父进程或子进程尝试写入这些共享的页面(以页为单位),操作系统会为发起写操作的进程(父进程或子进程)分配一个新的物理内存页, 并复制数据到这个页。

写时复制机制确保只有在必要时才复制数据页,这极大地减少了内存使用和提高了效率。

 

http://www.xdnf.cn/news/429463.html

相关文章:

  • solidwors插件库收集
  • 社区商业增值服务生态薄弱?停车反哺+商户联盟激活双向收益
  • 最大子段和(递推)
  • 2.4GHz无线通信芯片选型指南:集成SOC与低功耗方案解析
  • Python+1688 API 开发教程:实现商品实时数据采集的完整接入方案
  • 云蝠智能大模型呼叫接入通义千问qwen3模型!
  • 2025年RIS SCI2区,改进白鲸优化算法+复杂非线性方程组求解,深度解析+性能实测
  • 超标量处理器设计5-指令集体系
  • uniapp+vue3开发项目之引入vuex状态管理工具
  • 修改(替换)文件中的指定内容并保留文件修改前的时间(即修改前后文件的最后修改时间保持不变)
  • 我们该如何使用DeepSeek帮我们减负?
  • 深度Q网络(DQN)的基本概念
  • 【WebApi】YiFeiWebApi接口安装说明
  • JVM Optimization Learning(七)-GC
  • HttpSession 的运行原理
  • 利用自适应双向对比重建网络与精细通道注意机制实现图像去雾化技术的PyTorch代码解析
  • C语言中的assert
  • Trae IDE:AI深度集成的智能开发环境
  • Linux下使用systemd部署c++服务
  • 星云智控自定义物联网实时监控模板-为何成为痛点?物联网设备的多样化-优雅草卓伊凡
  • 武汉大学无人机视角下的多目标指代理解新基准!RefDrone:无人机场景指代表达理解数据集
  • 推荐算法工程化:ZKmall模板商城的B2C 商城的用户分层推荐策略
  • c++STL-通用(反向)迭代器适配器
  • vue 中绑定样式 【style样式绑定】
  • Deepseek+Xmind:秒速生成思维导图与流程图
  • 聊天项目总结
  • 《操作系统真象还原》第十四章(2)——文件描述符、文件操作基础函数
  • 浅聊一下数据库的索引优化
  • 基于PHP的九宫格抽奖系统设计与实现 九宫格抽奖系统开发与实现(PHP+MySQL)抽奖逻辑、奖品发放与活动管理
  • 《Python星球日记》 第67天:Transformer 架构与自注意力机制