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

Linux--fork

一、fork入门知识

  fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。可以简单地说fork()的作用就是创建一个子进程。

  一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

什么是进程

1)进程是动态的,程序是静态的

当一个程序调用的时候,就创建了一个进程;进程在运行的时候是具有独立性的,不影响其他进程

2)进程=内核数据结构+进程的代码和数据

代码:只读

数据:当有一个执行流尝试修改数据的时候,OS会自动给我们当前进程触发写时拷贝
写时拷贝(copy-on-write, COW)就是等到修改数据时才真正分配内存空间,这是对程序性能的优化,可以延迟甚至是避免内存拷贝,当然目的就是避免不必要的内存拷贝。

 这里引入一个概念叫做PCB:进程控制块。也就是linux自己创建的Task_struct结构体。进程控制块是系统为了管理进程设置的一个专门的数据结构,用它来记录进程的外部特征,描述进程的运动变化过程。

子进程完全拷贝父进程的PCB,但并不是同一个;父子进程代码共享,数据独有;同一个变量在父子进程>    的地址完全一样,OS中虚拟内存机制保证父子进程运行独立互不干扰

创建一个子进程实际上是创建了一个PCB,父进程与子进程看到的是同一份代码和数据

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

fork出错可能有两种原因:

1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
2)系统内存不足,这时errno的值被设置为ENOMEM。

二、fork进阶知识

以下面的代码为例,使用<unistd.h>头文件,调用fork()函数。其中getpid()函数的作用是获取进程id,getppid()函数的作用是获取父进程id

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{printf("AAAAA\n");fork();printf("BBBBBBBBB   pid:%d   ppid:%d\n",getpid(),getppid());                              sleep(1);return 0;
}

运行后的结果是

 

可以看出AAAAA只打印了一行,因为此时并没有执行fork()函数,只有初始执行的代码。之后通过fork()函数创建了一个子进程,因此BBBBBBBB打印了两次。

第一次打印B的时候,pid:25251 ppid:25728。而第二次打印B的时候,pid:28252 ppid:25251父进程的进程id与第一次打印的进程id相同。

因此可以说明fork()函数创建了一个id为28252的子进程,它的父进程id为28251

下面来考虑循环中使用fork()的效果

#include <unistd.h>
#include <stdio.h>int main(void)
{int i = 0;printf("i son/pa ppid pid  fpid/n");//ppid指当前进程的父进程pid//pid指当前进程的pid,//fpid指fork返回给当前进程的值for(i = 0; i < 2; i++){pid_t fpid = fork();if(fpid == 0)printf("%d child  %4d %4d %4d/n", i, getppid(), getpid(), fpid);elseprintf("%d parent %4d %4d %4d/n", i, getppid(), getpid(), fpid);}return 0;
}

 运行结果是:

i son/pa ppid pid  fpid
0 parent 2043 3224 3225
0 child  3224 3225    0
1 parent 2043 3224 3226
1 parent 3224 3225 3227
1 child     1 3227    0
1 child     1 3226    0

第一步:在父进程中,指令执行到for循环中,i=0,接着执行fork,fork执行完后,系统中出现两个进程,分别是p3224和p3225(后面我都用pxxxx表示进程id为xxxx的进程)。可以看到父进程p3224的父进程是p2043,子进程p3225的父进程正好是p3224。我们用一个链表来表示这个关系:

p2043->p3224->p3225

第一次fork后,p3224(父进程)的变量为i=0,fpid=3225(fork函数在父进程中返向子进程id)

p3225(子进程)的变量为i=0,fpid=0(fork函数在子进程中返回0)

第二步:假设父进程p3224先执行,当进入下一个循环时,i=1,接着执行fork,系统中又新增一个进程p3226

对于此时的父进程p2043->p3224(当前进程)->p3226(被创建的子进程)

对于子进程p3225,执行完第一次循环后,i=1,接着执行fork,系统中新增一个进程p3227

p3224->p3225(当前进程)->p3227(被创建的子进程)

从输出可以看到p3225原来是p3224的子进程,现在变成p3227的父进程。父子是相对的

第三步:第二步创建了两个进程p3226,p3227,这两个进程执行完printf函数后就结束了,因为这两个进程无法进入第三次循环,无法fork,该执行return 0;了,其他进程也是如此。

细心的读者可能注意到p3226,p3227的父进程难道不该是p3224和p3225吗,怎么会是1呢?这里得讲到进程的创建和死亡的过程,在p3224和p3225执行完第二个循环后,main函数就该退出了,也即进程该死亡了,因为它已经做完所有事情了。p3224和p3225死亡后,p3226,p3227就没有父进程了,这在操作系统是不被允许的,所以p3226,p3227的父进程就被置为p1了,p1是永远不会死亡的

 对于这种N次循环的情况,执行printf函数的次数为2*(1+2+4+……+2N-1)次,创建的子进程数为1+2+4+……+2N-1个。

printf的缓冲机制:printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上。

但是,只要看到有/n 则会立即刷新stdout,因此就马上能够打印了

相关文章:

Linux--fork

一、fork入门知识 fork&#xff08;&#xff09;函数通过系统调用创建一个与原来进程几乎完全相同的进程&#xff0c;也就是两个进程可以做完全相同的事&#xff0c;但如果初始参数或者传入的变量不同&#xff0c;两个进程也可以做不同的事。可以简单地说fork()的作用就是创建一…...

计算机组成原理(一)

1.了解计算机硬件的发展和软件的发展历程&#xff1b; 硬件&#xff1a;   电子管时代&#xff08;1946-1959&#xff09;&#xff1a;电子管、声汞延迟线、磁鼓   晶体管时代&#xff08;1959-1964&#xff09;&#xff1a;晶体管、磁芯   中、小规模集成电路时代&#…...

【SpringBoot】实现Async异步任务

1. 环境准备 在 Spring Boot 入口类上配置 EnableAsync 注解开启异步处理。 创建任务抽象类 AbstractTask&#xff0c;并分别配置三个任务方法 doTaskOne()&#xff0c;doTaskTwo()&#xff0c;doTaskThree()。 public abstract class AbstractTask {private static Random r…...

Node =>Express学习

1.Express 能做什么 能快速构建web网站的服务器 或 Api接口的服务期 Web网站服务器&#xff0c;专门对外提供Web网页资源的服务器Api接口服务器&#xff1a;专门对外提供API接口的服务器 2.安装 在项目所处的目录中&#xff0c;运行以下命令&#xff0c;简装到项目中了 npm …...

QT基础入门【布局篇】消除控件之间的间隔

一、相关参数 layoutLeftMargin: layout内的布局距离边框左端的距离。 layoutTopMargin: layout内的布局距离边框顶端的距离。 layoutRightMargin: layout内的布局距离边框右端的距离。 layoutBottomMargin: layout内的布局距离边框底端的距离。 layoutHorizontalSpacing: layo…...

vue脚手架 element-ui spring boot 实现图片上传阿里云 并保存到数据库

一.阿里云 注册登陆就不讲了&#xff0c;登陆进去后如下操作 1. 进入对象存储OSS 创建一个新的Bucket 随后点击新建的bucket 2.去访问RAM 前往RAM控制台 3.去创建用户 4.创建密匙 5.随后返回RAM控制台 给用户增加权限&#xff0c;文件上传所需权限&#xff0c;需要带含有…...

【FPGA】Verilog:组合电路 | 3—8译码器 | 编码器 | 74LS148

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;编码/译码器的应用 ​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器&…...

GLP-1类药物研发进展-销售数据-上市药品前景分析

据一项2021 年的报告发现&#xff0c;当 GLP-1 类似物用于治疗 2 型糖尿病时&#xff0c;全因死亡率降低了 12%&#xff0c;它们不仅降糖效果显著&#xff0c;同时还兼具减重、降压、改善血脂谱等作用。近几年&#xff0c;随着GLP-1R激动剂类药物市场规模不断增长&#xff0c;美…...

C++远程监控系统接收端- RevPlayMDIChildWnd.cpp

void CRevPlayWnd::InitMultiSock() { int RevBuf; int status; BOOL bFlag; CString ErrMsg; SOCKADDR_IN stLocalAddr; SOCKADDR_IN stDestAddr; SOCKET hNewSock; int RevLensizeof(RevBuf); //创建一个IP组播套接字 MultiSock W…...

QT之OpenGL深度测试

QT之OpenGL深度测试1. 深度测试概述1. 1 提前深度测试1.2 深度测试相关函数2. 深度测试精度2.1 深度冲突3. Demo4. 参考1. 深度测试概述 在OpenGL中深度测试(Depth Testing)是关闭的&#xff0c;此时在渲染图形时会产生一种现象后渲染的会把最先渲染的遮挡住。而在启用深度测试…...

用LCR测试仪测试无线充电系统中的线圈

宽阻抗范围用来表征电感和质量因数– 高精度 DCR 测量– 制造环节快速测量– 大量夹具可供选择智能终端上不断增加新功能&#xff0c;电池寿命成为用户最头痛的问题之一。相比便携式电源和电缆供电而言&#xff0c;无线充电技术因其方便性和多功能性获得了很大的关注&#xff0…...

华为、南卡和漫步者蓝牙耳机怎么选?国产高性价比蓝牙耳机推荐

随着蓝牙耳机的快速发展&#xff0c;现如今使用蓝牙耳机的人也越来越多。其中&#xff0c;日益增多的国产蓝牙耳机品牌也逐渐被大众认识、认可。目前一些热销的国产蓝牙耳机&#xff0c;如华为、南卡和漫步者等都是大家比较熟知的品牌。那么&#xff0c;这三个品牌哪个性价比高…...

MySQl学习(从入门到精通12)

MySQl学习&#xff08;从入门到精通12&#xff09;第 15 章_存储过程与函数1. 存储过程概述1. 1 理解1. 2 分类2. 创建存储过程2. 1 语法分析2. 2 代码举例3. 调用存储过程3. 1 调用格式3. 2 代码举例3. 3 如何调试4. 存储函数的使用4. 1 语法分析4. 2 调用存储函数4. 3 代码举…...

08讲 | 基于STM32单片机NBIOT定位实战项目

前言 绘制基于 STM32 单片机的 NBIOT 实战开发板。 文章目录前言一、原理图1、绘制1&#xff09;电源供电a、USB 转 TTL 电路b、锂电池充电管理电路c、3.3V电压转换电路d、一键开关机电路2&#xff09;单片机最小系统3&#xff09;ADC电压转换电路4&#xff09;NBIOT 模组串口电…...

提取接近竖直物体(粗定位)

由于项目的需要提取图像之中的一个接近于竖直的物体&#xff0c;一般的方法是进行图像分割&#xff0c;分割方式使用什么OTSU方式以及hsv方法等等。但是项目中使用的相机是黑白相机&#xff0c;会受到一定的限制。因此想到的是使用线条提取方式。线条提取方式之中最好的方法是使…...

程序环境和预处理

目录一、程序的翻译环境和执行环境二、编译链接2.1 翻译环境2.2 编译2.2.1 预处理2.2.2 编译2.2.3 汇编2.3 链接2.4 结果三、运行环境四、预处理详解4.1 #define4.1.1 #define定义标识符4.1.2 #define定义宏4.1.3 #define 替换规则4.1.4 #和##4.1.5 带副作用的宏参数4.1.6 宏和…...

财报解读:业务复苏迹象明显,中国中免能否重写增长神话?

2月3日&#xff0c;中国中免披露2022年度业绩快报&#xff0c;2022年总营收为544.63亿元&#xff0c;同比下降19.52%&#xff1b;实现归属于上市公司股东的净利润50.25亿元&#xff0c;同比下降47.95%。来源&#xff1a;中国中免2022年度业绩快报业绩近乎腰斩&#xff0c;但从长…...

macOS中虚拟机桥接模式分配静态ip

1.首先使用dhclient命令&#xff0c;在局域网中分配一个C类地址。 2.获得地址后&#xff0c;输入ifconfig&#xff0c;查看分配的地址。 3.然后编辑vi /etc/sysconfig/network-scripts/ifcfg-en***文件 在该配置文件中编辑&#xff0c;设置ONBOOTyes&#xff0c;而后添加静态配…...

prometheus increase函数统计得到小数

今天发现prometheus的increase函数得到了小数&#xff0c;研究一下源码&#xff0c;以下是rate/increase/delta 对应的计算函数https://github.com/prometheus/prometheus/blob/d77b56e88e3d554a499e22d2073812b59191256c/promql/functions.go#L55// extrapolatedRate is a uti…...

C++学习记录——유 类和对象(3)

文章目录1、赋值运算符重载1、运算符重载1、理解2、运算符重载实例2、赋值运算符重载2、日期类的实现1、加减函数1、加函数2、减函数2、前/后置--重载3.两个日期相减其他1、流插入2、流提取日期类的整体实现代码: https://gitee.com/kongqizyd/start-some-c-codes-for-learning…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合

无论是python&#xff0c;或者java 的大型项目中&#xff0c;都会涉及到 自身平台微服务之间的相互调用&#xff0c;以及和第三发平台的 接口对接&#xff0c;那在python 中是怎么实现的呢&#xff1f; 在 Python Web 开发中&#xff0c;FastAPI 和 Django 是两个重要但定位不…...

ArcPy扩展模块的使用(3)

管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如&#xff0c;可以更新、修复或替换图层数据源&#xff0c;修改图层的符号系统&#xff0c;甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql

安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了&#xff0c;系统很多命…...