fork函数详解【Linux】

fork函数详解【Linux】

  • fork函数的概念
  • fork调用后的底层细节
  • 解释fork学习中的一些笔记和问题
  • fork的写实拷贝
    • 深拷贝的策略
  • fork调用失败的原因

fork函数的概念

  调用fork函数可以在已存在的进程中创建一个子进程,此时,新进程叫做子进程,原进程叫做父进程。

  #include <unistd.h>
  pid_t fork(void);
 其中pid_t的底层是int;
在这里插入图片描述
返回值::子进程中返回0,父进程返回子进程id,出错返回-1
也就是这样:

#include <iostream>
#include <unistd.h>
int main()
{pid_t fd = fork();if (fd == 0){//this area is child}else if(fd > 0){// this area is parent}else{// this area is error}return 0;
}

fork调用后的底层细节

  当我们在用户空间调用了fork以后,控制会从用户空间转移到内核空间,因为fork属于系统调用,然后内核会:

  1. 为子进程分配新的内存块和内核数据结构。
  2. 以父进程为模板,将父进程的pcb和虚拟内存地址以及页表汇中的内容完整复制一份给子进程,以至于虚拟内存地址和页表以及页表和物理地址空间的映射关系,父子进程此时都是一模一样的。
  3. 将子进程的pcb添加到系统进程列表中。
  4. fork返回,开始进程调度器调度。

解释fork学习中的一些笔记和问题

  1. 同一个程序,每次启动运行时,分配的pid都可能不同。
  2. 命令行中的父进程一般是命令行解释器bash,命令行中启动的进程,都是bash的子进程。
  3. Linux中创建子进程有两种方式:
    3.1. 在命令行行中直接启动进程。(启动进程的本质就是创建进程吗)
    3.2. 通过代码来创建子进程。(一般是由父进程创建)
  4. 只有父进程执行fork之前的代码,fork之后的代码父子进程都要执行。
  5. 创建子进程的原因:想让子进程协助父进程完成一些工作,这些工作是单进程完成不了的。(比如边下载边播放视频),创建子进程是为了和父进程做不一样的事。
  6. 为什么fork的两个返回值会给父进程返回子进程pid,给子进程返回0?
    :答:因为父子进程的数量比例是 1:n , 为了使得父子进程能够一一对应,具有唯一性,且子进程主要是为了协助父进程,父进程得到了子进程的pid能够确定唯一的子进程,方便调用子进程。
  7. fork之后,父子进程谁先运行?
    : 答:这个跟内核的调度机制有关,哪一个进程的pcb先被选择调度,哪一个进程就先执行,所以是不确定的。由各自pcb中的调度信息(时间片,优先级)和调度器算法决定,也就是有OS决定。

fork的写实拷贝

  由于虚拟内存地址和页表以及页表和物理地址空间的映射关系,父子进程此时都是一模一样的。所以可以说父子继承一开始都是使用同一块地址空间。

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main()
{int a = 8;pid_t fd = fork();if (fd == 0){a = 3;std::cout << "child: " << a << std::endl;}if (fd > 0){std::cout << "parent: " << a << std::endl;}wait(NULL);return 0;
}

在这里插入图片描述
  看完上面这份代码,为什么明明父子进程的a是同一块地址空间的,按理来说子进程修改了a为3,父进程的a为什么还是8呢?难道是结论错误了吗?

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main()
{int a = 8;std::cout << &a << std::endl;pid_t fd = fork();if (fd == 0){a = 3;std::cout << "child: " << &a << std::endl;}if (fd > 0){std::cout << "parent: " << &a << std::endl;}wait(NULL);return 0;
}

在这里插入图片描述
  通过上面这个代码也可以清楚知道父子进程的a指向的地址空间确实是同一个。

  这里的原因是因为我们所看到的地址叫做虚拟内存空间,每一个进程都会有一份虚拟内存和一个页表。但是物理内存只有一个,页表中保存着虚拟内存和物理内存之间的一份映射关系。

  我们可以浅显的将页表看做下图(真正页表中的字段不止三个,但是此刻这三个字段足以说明问题);
在这里插入图片描述
  所以真实情况是:子进程的创建确实以父进程为模板将其内容拷贝到了子进程的内核数据结构中,但是当数据有所变化时,就以深拷贝的方式父子进程各自私有一份。

深拷贝的策略

  1. 父进程创建子进程的时候会先将自己页表中的访问权限字段中的读写权限改为只读,然后再创建,使得父子进程的数据都是只读。
  2. 当父子进程任意一方试图更改共同数据,就会触发页表权限问题,在页表映射转换时出现权限问题会有两种情况:
    • 真的出错了
    • 不是出错,触发深拷贝的策略机制,需要进程重新申请内存
      此时显然是属于后者。
  3. 此时再物理内存中开辟了一段新空间,然后将更改后的数据写入到内存,页表中的物理地址也要改成新物理空间的地址。
  4. 因为没有更改虚拟地址,所以我们打印出来的地址会发现深拷贝之后的虚拟地址依旧没有改变。这也就解释了开头那份代码所带来的问题。

在这里插入图片描述

fork调用失败的原因

  • 系统中有太多的进程
  • 实际用户的进程数超过了限制

    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/581855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 入参校验及全局异常处理

版本依赖 JDK 17 Spring Boot 3.2.0 源码地址&#xff1a;Gitee Spring Boot validation spring-boot-starter-validation是基于hibernate-validator的实现&#xff0c;在Spring Boot项目中直接导入spring-boot-starter-validation即可。 Valid 和 Validated 的区别 适用范围…

《对话品牌》——活到老“养”到老

本期节目《对话品牌》栏目组邀请到了深圳壹常青健康管理有限公司董事长邬锡娣女士参加栏目录制&#xff0c;分享其企业故事&#xff0c;树立品牌形象&#xff0c;提升品牌价值&#xff01; 节目嘉宾&#xff1a;邬锡娣女士 节目主持人&#xff1a;董倩 节目播出平台&#xf…

在线教育系统源码解读:定制化企业培训APP的开发策略

当下&#xff0c;企业培训正经历着一场数字化的迭代&#xff0c;定制化企业培训APP应运而生&#xff0c;成为提升员工技能、推动企业发展的重要工具。下文小编将与大家一同深入了解在线教育系统的源码&#xff0c;探讨开发定制化企业培训APP的策略&#xff0c;以满足不同企业的…

C#获取windows系统资源使用情况

1.前言 之前有一篇博客介绍如何获取Linux服务器上的资源使用情况《Java 获取服务器资源&#xff08;内存、负载、磁盘容量&#xff09;》&#xff0c;这里介绍如何通过C#获取Window系统的资源使用。 2.获取服务器资源 2.1.内存 [DllImport("kernel32.dll")][retu…

jenkins解决工具找不到的问题

--------------------------插件选择版本最好能跟服务器对上

香橙派5plus从ssd启动Ubuntu

官方接口图 我实际会用到的就几个接口&#xff0c;背面的话就一个M.2固态的位置&#xff1a; 其中WIFI模块的接口应该也可以插2230的固态&#xff0c;不过是pcie2.0的速度&#xff0c;背面的接口则是pcie3.0*4的速度&#xff0c;差距还是挺大的。 开始安装系统 准备工作 一张…

C语言中关于switch语句的理解

首先我们来看一下switch的定义 switch&#xff08;整型表达式&#xff09; { case 整型常量表达式: 语句&#xff1b; } 我们在书写时要注意一下&#xff0c;无论是在switch还是case&#xff0c;后面跟着的都一定要是整型&#xff0c;而且case这一行写完时&#xff0c;最后要用…

图片放大后变模糊了怎么办?这个方法惊艳你

我们需要了解为什么图片放大会模糊。在照片放大时&#xff0c;像素也会随之增加。如果图片的像素不足&#xff0c;那么放大后每个像素的大小也会增加&#xff0c;从而导致细节模糊。 那么&#xff0c;面对这个问题&#xff0c;我们该如何解决呢&#xff1f;别急&#xff0c;让…

狗笼,预计2028年将以 6.2%的复合年增长率增长

对于想要为爱犬提供安全舒适空间的宠物主人来说&#xff0c;狗笼是必不可少的宠物配件。由于宠物主人的数量不断增加以及人们对宠物安全和福祉的意识不断增强&#xff0c;狗笼市场一直在稳步增长。 全球市场分析&#xff1a;全球狗笼市场预计从 2021 年到 2028 年将以 6.2% 的复…

axios配置请求头content-type 和 get/post请求方式

axios配置请求头content-type https://blog.csdn.net/wojiushiwo945you/article/details/107653962 axios 是Ajax的一个插件&#xff0c;axios虽然是一个插件&#xff0c;但是我们不需要通过Vue.use(axios)来使用&#xff0c;下载完成后&#xff0c;只需在项目中引入即可。(一…

NFC刷卡soc芯片SI3262集成刷卡+触摸+ACD超低功耗一体

简介 13.56mhz刷卡soc芯片SI3262集成刷卡触摸ACD超低功耗&#xff0c;ACD模式刷卡距离可达到5cm以上&#xff0c;非常适用于小体积门锁&#xff0c;密码锁&#xff0c;柜锁&#xff0c;接下来介绍一下这款芯片的具体功能。 优势 1.超低功耗&#xff0c;最低功耗达 1.7uA&…

揭秘跨境电商ERP源码定制化需求及最佳实践

跨境电商ERP源码的定制化需求是跨境电商企业在整个ERP系统开发实施过程中需要重点关注的问题之一。本文将围绕跨境电商ERP源码定制化的需求和最佳实践展开深入探讨&#xff0c;为行业内的从业者和相关人士提供一些建议和思路。 定制化需求 跨境电商ERP的业务特点决定了对源码…

8.小明和完美序列

题目 import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();sc.nextLine();Map<Integer,Intege…

Flask登陆后登陆状态及密码的修改和处理

web/templates/common 是统一布局 登录成功 后flask框架服务器默认由login.html进入仪表盘页面index.html(/),该页面的设置在 (web/controllers/user/index.py)&#xff0c;如果想在 该仪表盘页面 将 用户信息 展示出来&#xff0c;就得想办法先获取到 当前用户的 登陆状态。…

2022年全国职业院校技能大赛高职组云计算正式赛卷第三场-公有云

2022 年全国职业院校技能大赛高职组云计算赛项试卷 【赛程名称】云计算赛项第三场-公有云 目录 2022 年全国职业院校技能大赛高职组云计算赛项试卷 【赛程名称】云计算赛项第三场-公有云 【任务 1】公有云服务搭建[10 分] 【任务 2】公有云服务运维[10 分] 【任务 3】公有云运维…

03.MySQL的体系架构

MySQL的体系架构 一、MySQL简介二、MySQL的体系架构三、MySQL的内存结构四、MySQL的文件结构 一、MySQL简介 MySQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典MySQL AB公司开发&#xff0c;后被Sun公司收购&#xff0c;Sun公司被Oracle…

文件操作安全之-目录穿越流量告警运营分析篇

本文从目录穿越的定义,目录穿越的多种编码流量数据包示例,目录穿越的suricata规则,目录穿越的告警分析研判,目录穿越的处置建议等几个方面阐述如何通过IDS/NDR,态势感知等流量平台的目录穿越类型的告警的线索,开展日常安全运营工作,从而挖掘有意义的安全事件。 目录穿越…

鸿蒙Harmony(八)ArkUI--状态管理器之@State

状态管理 在声明式UI中&#xff0c;是以状态驱动视图更新 状态&#xff1a;指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09; StateProp 和 LinkProvide和 Consume State State装饰器标记的变量必须初始化&#xff0c;不能为空值State支持Object 、class、…

【PostgreSQL内核学习(二十)—— 数据库中的遗传算法】

数据库中的遗传算法 概述个体的编码方式及种群初始化geqo 函数 适应值geqo_eval 函数gimme_tree 函数 父体选择策略geqo_selection 函数 杂交算子边重组杂交 ERX ( edge recombination crossover)gimme_edge_table 函数gimme_tour 函数 变异算子geqo_mutation 函数 声明&#x…

Java EE 网络原理之HTTP 响应详解

文章目录 1. 认识"状态码"(status code)2. 通过 form 表单构造 HTTP 请求3. 通过 ajax 构造 HTTP 请求 1. 认识"状态码"(status code) 表示了这次请求对应的响应&#xff0c;是什么样的状态 &#xff08;成功&#xff0c;失败&#xff0c;其他的情况&…