fork函数详解【Linux】

这篇具有很好参考价值的文章主要介绍了fork函数详解【Linux】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

fork函数的概念

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

  #include <unistd.h>
  pid_t fork(void);
 其中pid_t的底层是int;
fork函数详解【Linux】,系统编程,linux,运维,服务器,c++,学习方法
返回值::子进程中返回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;
}

fork函数详解【Linux】,系统编程,linux,运维,服务器,c++,学习方法
  看完上面这份代码,为什么明明父子进程的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;
}

fork函数详解【Linux】,系统编程,linux,运维,服务器,c++,学习方法
  通过上面这个代码也可以清楚知道父子进程的a指向的地址空间确实是同一个。

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

  我们可以浅显的将页表看做下图(真正页表中的字段不止三个,但是此刻这三个字段足以说明问题);
fork函数详解【Linux】,系统编程,linux,运维,服务器,c++,学习方法
  所以真实情况是:子进程的创建确实以父进程为模板将其内容拷贝到了子进程的内核数据结构中,但是当数据有所变化时,就以深拷贝的方式父子进程各自私有一份。

深拷贝的策略

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

fork函数详解【Linux】,系统编程,linux,运维,服务器,c++,学习方法

fork调用失败的原因

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

    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄文章来源地址https://www.toymoban.com/news/detail-771211.html

到了这里,关于fork函数详解【Linux】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux多线程与fork()函数

    4.1多线程中使用进程复制 在使用fork()函数之后,没有判断返回值大于0还是等于0,则之后的代码在父子进程都会执行。   pid相同的为父进程中的两个线程,pid不同的为子进程的线程。此时子进程启动的为父进程的 主线程 所在的执行路径。 当把fork()从主线程中放到子线程中时

    2024年02月11日
    浏览(65)
  • 【Linux】fork函数的基础知识

    文章目录 前言 一、fork的返回值 二、常见问题 1.为什么fork要给子进程返回0,给父进程返回子进程pid? 2.一个函数返回两次值怎么理解? 3.一个变量怎么会有不同的内容? 4.fork函数干了什么? fork初识: 1.fork有两个返回值。 2.父子进程代码共享,数据各开辟空间,私有一份(

    2024年02月10日
    浏览(41)
  • 【Linux】进程查看|fork函数|进程状态

    🦄 个人主页—— 🎐 开着拖拉机回家_Linux,大数据运维-CSDN博客 🎐✨🍁 🪁🍁🪁🍁🪁🍁🪁🍁 🪁🍁🪁🍁🪁🍁🪁 🪁🍁🪁🍁🪁🍁🪁🍁🪁🍁🪁🍁 感谢点赞和关注 ,每天进步一点点!加油! 目录 一、基本概念 1.1 概念提出 1.2 特征 二、描述进程-PCB 2.1 什么是进程

    2024年02月04日
    浏览(43)
  • Linux------进程的fork()详解

    目录 前言 一、fork()的使用 二、fork()的返回值 我们为什么要创建子进程? 父进程与子进程的分流 三、fork的一些难理解的问题 1.fork干了什么事情? 2.fork为什么会有两个返回值  3.fork的两个返回值,为什么会给父进程返回子进程pid,给子进程返回0? 4.fork之后,父子进程谁先

    2024年01月18日
    浏览(40)
  • UNIX/LINUX fork函数的问题 并不适合共享

    一位朋友问我一个关于 socket 通信的相关问题,其需要解决的问题如下: 需要存在一个服务器进程,服务器进程会进行监听,负责建立与客户端的socket连接,同时可以存在多个客户端进程,客户端进程之间可以进行通信,不过客户端之间并不会建立socket连接,通信是通过将信

    2024年02月16日
    浏览(33)
  • Linux系统运维:性能监视和分析工具sar命令详解

    目          录 一、sar工具介绍 二、sar工作原理 (一)原理概述 (二)sar数据收集器 三、sar命令语法 四、sar主要功能介绍 (一)功能概述 (二)CPU统计数据 (三)磁盘I/O统计数据 (四)网络统计数据 1、是使用-n DEV选项的sar输出 2、关于网络错误的信息可以用sar -n EDE

    2024年02月21日
    浏览(73)
  • Linux网络编程:socket & fork实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(51)
  • 华为云云耀云服务器L实例评测 | Linux系统宝塔运维部署H5游戏

    本章节内容,我们主要介绍华为云耀服务器L实例,从云服务的优势讲起,然后讲解华为云耀服务器L实例资源面板如何操作,如何使用宝塔运维服务,如何使用运维工具可视化安装nginx,最后部署一个自研的H5的小游戏(6岁的小朋友玩的很开心😁)。 前端的同学如果想把自己

    2024年02月07日
    浏览(58)
  • Linux高性能服务器编程|阅读笔记:第6章 - 高级I/O函数

    Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~   ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿

    2024年02月03日
    浏览(41)
  • Linux网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包