Linux 复制进程fork

一、父进程和子进程

当前的一个进程在fork的时候可以复制当前的进程产生一个进程,这时产生出来的这个进程就是子进程,被复制的进程叫做父进程。子进程会将环境变量从父进程继承过来,或者说被拷贝过来。父进程也会有它的父进程,一层一层往上走,最顶头的父进程是读取了一些文件才得到了这些环境变量的值,这样的话一个进程就有了,这个进程有了之后,就会把这些环境变量的值传给它后边的进程,它后边的进程一直往后传。

在运行一个程序的时候,这个程序处在内存中,给这个程序分配内存空间,fork产生的子进程也要给它分配内存空间,原来的父进程需要多少内存空间,复制出来的子进程就需要多少内存空间,系统原来描述父进程有一个PCB,现在产生的子进程也需要有一个PCB,也就是所有父进程的资源都要拷贝一份给子进程,父进程和子进程一模一样,两个进程一起执行。但是子进程不是从头开始执行,是从fork复制的位置开始执行。

二、 fork 方法

语法形式:

pid_t  fork(void)

函数返回类型pid_t实质是int类型。这个pid_t实际上就是进程的一个id号,所以它实际上就是一个整型值。

这个返回值比较复杂,因为fork之后会变成两个进程,一个父进程,一个子进程,fork 函数新生成的一个进程就是子进程。调用fork函数的进程为父进程,新生成的进程为子进程。 这个fork会在父进程中返回一个值,这个值是子进程的pid,即子进程的id号;在子进程中也返回一个值,子进程中返回的是0,如果失败则返回-1。也就是说,在父进程中返回子进程的pid,在子进程中返回0,失败返回-1。

fork执行之后会有父进程和子进程两个进程,两个进程都执行同一套代码,区分到底是父进程在执行,还是子进程在执行,就看fork的返回值。父进程中fork的返回值是大于0的,子进程中fork的返回值等于0。

1.当前进程复制产生一个子进程的过程

代码如下图所示:

在这里插入图片描述

以返回值作为判断是父进程在执行还是子进程在执行的条件,然后循环输出父进程和子进程的执行结果。

编译并执行以上代码:

在这里插入图片描述

从结果可以看出子进程和父进程两个进程并发运行,无论是先执行父进程还是先执行子进程都是可以的。

2.当前进程复制产生一个子进程之后子进程和父进程当前的pid是怎样的?

在这里插入图片描述

通过getpid()得到当前进程的pid。

编译并运行以上代码:

在这里插入图片描述

根据运行结果可以看出子进程比父进程的pid大,这是因为子进程是父进程复制而来的,子进程肯定比父进程晚一些。

当前进程复制产生一个子进程的过程分析:

当程序执行到fork之后,就把当前的进程复制了一份,产生子进程,即子进程和父进程,两个进程分别执行,两个进程具有相同的代码,假设如上述代码当前父进程的pid为264088,新产生出来的子进程的pid为264089。

当fork执行完毕之后,接下来就从fork返回的地方开始继续执行,在当前父进程中fork的返回值就是子进程的pid,即264089,这时pid的值既不等于-1也不等于0,所以就是父进程在执行,跳转到代码中的

n=7;
s="parent";

这一部分,然后再去循环输出结果,输出的时候获取的pid是当前进程的pid,也就是父进程的pid,即264088。这时输出的s就是"parent"。

接下来到了子进程,子进程并不是从头开始执行,而是也从fork返回值得地方开始执行,子进程中fork的返回值是固定值0,所以这时子进程在执行,跳转到代码中的

n=3;
s="child";

这一部分,然后再去循环输出结果,输出的时候获取的pid是当前进程的pid,也就是子进程的pid,即264089。这时输出的s就是"child"。

仅仅由于fork的返回值不同,代码执行的分支不一样。

fork产生一个子进程之后fork就结束了,产生的子进程也不会无限fork下去,因为子进程是从fork带回返回值的位置开始执行。fork不会多次执行。同样在父进程中也不会多次执行fork,也是从fork返回值位置开始执行。

3.父进程和子进程的内存空间

代码如下图所示:

在这里插入图片描述

编译并运行的结果如下:

在这里插入图片描述
运行结果:n=3和n=7时,n的值不同,但是地址的值却是一样的。

分析:在物理内存中父进程和子进程用的不是同一块内存空间而是分开的,父进程用的是父进程的内存空间,子进程用的是子进程的内存空间。之所以运行结果中的地址是相同的,是因为那是逻辑地址,逻辑地址也就是距离起始位置的偏移量,逻辑地址相同是因为举例起始位置的偏移量相同,所以父进程和子进程的逻辑地址是相同的。打印的地址一般都是逻辑地址,而不是物理地址,物理地址一般看不到,物理地址要经过页表进行转换才能看到物理地址。正常情况下,程序中无法直接打印物理地址。

因此,父进程和子进程的逻辑地址是相同的,但是物理地址不相同。子进程的相对地址还是和父进程中一样的。

三、写时拷贝

假如父进程和子进程两个进程的内容暂时是一样的,现在只修改父进程中其中两个物理内存的值,其它物理内存不做任何修改,那么就把父进程中这两个物理内存的值各复制了一份给了子进程,子进程重新分配两个物理内存用来存放对应的值,接下来对于父进程中不做修改的物理内存,子进程中就不分配物理内存来存放这块物理内存中的值了,而是让子进程直接去使用父进程中没有被修改物理内存中的值,也就是没有被修改的物理内存就不会被复制一份给子进程,而是让父进程和子进程共享同一个物理内存。等到父进程或者子进程要修改被共享的物理内存时,父子进程就不能共享了,因为修改了之后,父进程和子进程对应的物理内存就不一样了,这时就只能把父进程被修改的物理内存的值复制一份给子进程,子进程重新分配物理内存来存放对应的值。

这个共享的过程就是写时拷贝,写时拷贝的目的是为了提高fork复制的性能。在写时拷贝的时候,系统记录这个内存正在被两个进程所引用,一旦其中一个进程结束之后,这块物理内存空间不会被释放掉。

写时拷贝对于用户来说时透明的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

四、Dubbo扩展点加载机制

四、Dubbo扩展点加载机制 4.1 加载机制概述 Dubbo良好的扩展性与框架中针对不同场景使用合适设计模式、加载机制密不可分 Dubbo几乎所有功能组件都是基于扩展机制(SPI)实现的 Dubbo SPI 没有直接使用 Java SPI,在它思想上进行改进&#xff…

【自用】云服务器 使用 docker 搭建 HomeAssistant + MQTT 物联网平台

总览 1.搭建流程概述 2.准备工作 3.开始搭建! 4.总结 如果想看 ESP32 或其他使用 MicroPython 编程的单片机如何连接到该云服务器,实现 HomeAssistant 控制 单片机的内容,请看我这篇博客的下一篇。 一、搭建流程概述 0.总体流程 我们需要…

这四种订货系统不能选(二):不能独立部署

订货系统在传统批发贸易企业数字化转型中扮演着重要的角色。然而,有一种类型的订货系统并不适合选择,那就是无法独立部署的系统。 无法独立部署的订货系统意味着数据必须存放在软件厂商的服务器上。当我们选择这样的系统时,需要确保系统具备强…

如何初始化Git仓库

如何将目录初始化为Git仓库 一级目录二级目录三级目录 一、准备1、安装 gh2、登录 二、初始化 Git 仓库 一级目录 二级目录 三级目录 一、准备 ​ 在这里,我们需要借助一个非常好用的工具,大家也可以参照官方文档进行阅读,下面介绍常用的…

从小白到大神之路之学习运维第79天-------Kubernetes网络组件详解

第四阶段 时 间:2023年8月14日 参加人:全班人员 内 容: Kubernetes网络组件详解 目录 一、Kubernetes网络组件 (一)Flannel网络组件 (二)Calico 网络插件 (1)…

算法与数据结构(二十三)动态规划设计:最长递增子序列

注:此文只在个人总结 labuladong 动态规划框架,仅限于学习交流,版权归原作者所有; 也许有读者看了前文 动态规划详解,学会了动态规划的套路:找到了问题的「状态」,明确了 dp 数组/函数的含义&a…

【RabbitMQ上手——单实例安装5种简单模式实现通讯过程】

【RabbitMQ入门-单实例安装&5种简单模式实现通讯过程】 一、环境说明二、安装RabbitMQ三、用户权限及Virtual Host设置四、5种简单模式实现通讯过程的实现五、小结 一、环境说明 安装环境:虚拟机VMWare Centos7.6 Maven3.6.3 JDK1.8RabbitMQ版本:…

Java面向对象(内部类)(枚举)(泛型)

内部类 内部类是五大成员之一(成员变量、方法、构造方法、代码块、内部类); 一个类定义在另一个类的内部,就叫做内部类; 当一个类的内部,包含一个完整的事物,且这个事务不必单独设计&#xf…

【深入理解ES6】字符串和正则表达式

概念 字符串(String)是JavaScript6大原始数据类型。其他几个分别是Boolean、Null、Undefined、Number、Symbol(es6新增)。 更好的Unicode支持 1. UTF-16码位 字符串里的字符有两种: 前 个码位均以16位的编码单元…

怎么开通Tik Tok海外娱乐公会呢?

TikTok作为全球知名的社交媒体平台,吸引了数亿用户的关注和参与。许多公司和个人渴望通过开通TikTok直播公会进入这一领域,以展示自己的创造力和吸引更多粉丝。然而,成为TikTok直播公会并非易事,需要满足一定的门槛和申请找cmxyci…

YAMLException: java.nio.charset.MalformedInputException: Input length = 1

springboot项目启动的时候提示这个错误:YAMLException: java.nio.charset.MalformedInputException: Input length 1 根据异常信息提示,是YAML文件有问题。 原因是yml配置文件的编码有问题。 需要修改项目的编码格式,一般统一为UTF-8。 或…

Die2Die(D2D)和chip2chip(C2C)之间的高速互联接口

随着chiplet的兴起,Die2Die的高速互联越来越重要,相比于传统的C2C(chip2chip)的互联,D2D的片间距离很近(10mm量级),且这些小的chip(裸片)最终形成一个封装【多芯片模块(MCM)】。所以D2D的互联信道短&#x…

[C++ 网络协议编程] UDP协议

目录 1. UDP和TCP的区别 2. UDP的工作原理 3. UDP存在数据边界 4. UDP的I/O函数 4.1 sendto函数 4.2 recvfrom函数 4. 已连接(connected)UDP套接字和未连接(unconnected)UDP套接字 5. UDP的通信流程 5.1 服务器端通信流程 5.2 客户端通信流程 1. UDP和TCP的区别 主要…

Oracle常用基础知识

整体介绍 SQL语言是一种数据库语言 1、DDL:数据定义语言 create-创建 drop-删除 alter-修改 rename-重命名 truncate-截断 2、DML:数据操作语句 insert-插入 delete-删除 update-更新 select-查询 3、DCL:数据控制语句 grant-授权 rev…

DTC服务(0x14 0x19 0x85)

DTC相关的服务有ReadDTCInformation (19) service,ControlDTCSetting (85) service和ReadDTCInformation (19) service ReadDTCInformation (19) service 该服务允许客户端从车辆内任意一台服务器或一组服务器中读取驻留在服务器中的诊断故障代码( DTC )信息的状态…

c语言——颠倒字符串顺序

//颠倒字符串顺序 //列如&#xff1a;我们将runningman利用递归翻转计算。 #include<stdio.h> void reverseSentence(); int main() {printf("字符串输入:");reverseSentence();return 0; }void reverseSentence() {char c;scanf("%c",&c);if(c!…

沁恒ch32V208处理器开发(三)GPIO控制

目录 GPIO功能概述 CH32V2x 微控制器的GPIO 口可以配置成多种输入或输出模式&#xff0c;内置可关闭的上拉或下拉电阻&#xff0c;可以配置成推挽或开漏功能。GPIO 口还可以复用成其他功能。端口的每个引脚都可以配置成以下的多种模式之一&#xff1a; 1 浮空输入 2 上拉输入…

Spring事务控制

目录 1、什么是事务控制 2、编程式事务控制 2.1、简介 2.2、相关对象 2.2.1、PlatformTransactionManager 2.2.2、TransactionDefinition 2.2.2.1、事务隔离级别 2.2.2.2、事务传播行为 2.2.3、TransactionStatus 3、声明式事务控制 3.1、简介 3.2、区别 3.3、⭐作…

做BI领域的ChatGPT,思迈特升级一站式ABI平台

8月8日&#xff0c;以「指标驱动 智能决策」为主题&#xff0c;2023 Smartbi V11系列新品发布会在广州丽思卡尔顿酒店开幕。 ​ 后疫情时代&#xff0c;BI发展趋势的观察与应对 在发布会上&#xff0c;思迈特CEO吴华夫在开场致辞中表示&#xff0c;当前大环境背景下&#xf…

Android Studio实现列表展示图片

效果&#xff1a; MainActivity 类 package com.example.tabulation;import android.content.Intent; import android.os.Bundle; import android.view.View;import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; im…