【Linux】进程控制-进程创建

目录

一、fork()是什么?

二、fork返回值问题

1、fork()的两个返回值是什么?

2、fork()为什么有两个返回值?

3、一个变量为什么会保存两个不同的值?

三、写时拷贝

1、写时拷贝是什么

2、为什么要写时拷贝

3、写时拷贝的示意图

四、fork()创建子进程时系统做了什么?

五、fork()常规用法

六、fork()函数相关补充

七、fork失败的原因?

1、系统中有太多进程

2、实际用户的进程数超过了限制


一、fork()是什么?

fork()是操作系统提供的一个函数,它可以从代码层面(已经存在的进程)上创建一个新的进程。

新的进程为子进程,原进程为父进程。

二、fork返回值问题

1、fork()的两个返回值是什么?

给子进程返回0,给父进程返回子进程的pid

1 #include<stdio.h>
  2 #include<unistd.h>
  3 
  4 int main()
  5 {
  6     pid_t id=fork();
  7     if(id<0)
  8     {
  9         printf("子进程创建失败\n");
 10         return 1;
 11     }
 12     else if( id==0 )
 13     {                                                                                                                
 14         //子进程
 15         while(1)
 16         {
 17             printf("我是子进程:pid: %d,ppid: %d\n",getpid(),getppid());
 18             sleep(1);
 19         }
 20     }
 21     else
 22     {
 23         //父进程
 24         while(1)
 25         {
 26             printf("我是父进程:pid: %d,ppid: %d\n",getpid(),getppid());
 27             sleep(1);
 28         }
 29     }
 30 }   

2、fork()为什么有两个返回值?

因为fork()函数内部,return会被执行两次,return的本质就是对id进行写入

3、一个变量为什么会保存两个不同的值?

父子进程各自都有地址空间,页表,用的虚拟地址一样,物理内存是被映射到不同区域的,当任何一方尝试修改数据时,发生了写时拷贝,如果子进程修改数据时,同一个变量经过虚拟地址空间映射,页表写时拷贝,会重新给子进程开辟空间,所以父子进程各自其实在物理内存中,有属于自己的变量空间,只不过在用户层用同一个变量(虚拟地址)来标识。

三、写时拷贝

1、写时拷贝是什么

写时拷贝时多进程创建时,保证父子进程独立性,尤其是数据层面上保证独立性的非常关键的策略,采用写时拷贝技术实现独立性,通过写时拷贝让父子进程数据不在相互干扰,也是一种延迟写入的过程,宏观上提高了整个内存的使用率。

2、为什么要写时拷贝

因为有写时拷贝技术的存在,所以父子进程得以彻底分开,完成了进程独立性的技术保证,

写时拷贝是一种延时申请技术,可以提高整机内存的使用率

对于数据而言

创建进程的时候,直接拷贝分离,可能拷贝到子进程根本就不会用到的数据空间,即便用到了,也可能只是读取,会造成空间浪费,因此创建子进程时,不需要将不会被访问的,或者只会读取的数据拷贝一份。

什么样的数据值得拷贝?

将来被父或者子进程写入的数据,但是即使是OS,无法知道哪些空间会被写入,即便提前拷贝了,可能并不会立即使用

所以OS选择了写时拷贝技术,来进行将父子进程的数据进行分离

因此回答了OS为何要选择写时拷贝技术,对父子进程进行分离

1、用的时候,在分配空间,是高效使用内存的一种表现

2、OS无法在代码执行前预知哪些空间会被访问

3、写时拷贝保证了进程的独立性

3、写时拷贝的示意图

fork()之后,子进程构建出来后数据结构以父进程为模板,把父进程相关字段拷贝起来,默认情况下指向的内容是完全一样的,对页表的读写权限为只读权限,如果子进程尝试修改物理内存中的内容,把内存中曾经被大家所共享的内存区域拷贝一份给子进程,修改页表当中的页表项,让子进程的页表指向新空间的地址,数据层面上两个进程实现了分离。任何一个进程尝试修改,都会发生写时拷贝,只读权限去掉了,两个进程已经分开,实现进程独立性。

四、fork()创建子进程时系统做了什么?

fork()创建子进程,本质是系统里多了一个进程,该进程有对应的PCB,对应的地址空间,对应的页表,并将自己进程对应的代码和数据加载到内存,构建映射关系,将该进程PCB放入到运行队列里,等待OS或调度器调度,一旦CPU调度该进程,此时可以通过虚拟地址空间和页表找到该进程的相关代码,然后从上往下执行顺序语句,循环判断,函数跳转,进而在进程内部执行进程内的代码,完成某件事情。

因此fork()执行后,OS会分配新的内存块和内核数据结构给子进程(创建对象),将父进程部分数据结构内容拷贝给子进程(赋值和初始化,子进程的相关数据是以父进程为模板的,包括优先级信息,状态信息),添加子进程到系统进程列表当中(如果无法直接运行,就列入到等待队列,阻塞或者挂起)fork返回,开始调度器调度(fork函数最后return时,子进程已经创建)

五、fork()常规用法

1、一个父进程希望复制自己,使父子进程同时指向不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求

2、一个进程要执行一个不同程序

六、fork()函数相关补充

1、创建子进程时,会给子进程分配对于的内核数据结构,这些都是子进程私有的,因为进程具有独立性!理论上,子进程也要有自己的代码和数据,可是一般而言,我们没有加载的过程,也就是说,子进程没有自己的代码和数据。我们知道代码时不可以被写入的,只能读取,数据可能会被修改,必须分离,因此创建子进程时,父子进程代码共享,数据以写时拷贝的方式各自持有一份

2、fork之后,父子进程代码共享是after之后还是所有代码共享?

1、我们的代码汇编后,会有很多行代码,每行代码加载到内存之后,都有对应的地址

2、因为进程随时可能被中断(还没执行完)下次回来还必须从之前的位置继续运行,就要求CPU必须记录下来当前进程执行的位置,所有CPU内有对应的寄存器数据,用来记录当前进程的执行位置!

3、寄存器在CPU内只有一份,寄存器内的数据可以有多份的,即进程的上下文数据,既然是数据创建的时候,要给子进程,虽然父子今进程各自调度,各自会修改EIP,但是已经不重要了,子进程已经认为EIP的起始值,就是fork之后的代码,子进程从after之后开始执行,并不代表之前的代码看不到。

七、fork失败的原因?

1、系统中有太多进程

OS系统创建一个进程要做什么?

要创建进程对应的内核数据结构task_struct,还要为该进程创建对应的地址空间mm_struct,还要为该进程创建页表,构建映射关系,并且还要将该进程对应的代码和数据加载到内存。

因此,进程创建本质要消耗内存资源,进程太多,导致系统内存资源不足,不让创建进程。

2、实际用户的进程数超过了限制

  1 //fork失败原因                                                                                                       
  2 //系统内存不足
  3 //系统给该用户创建的进程数是有上限的
  4 
  5 //测试系统创建多少个进程数会失败
  6 #include<stdio.h>
  7 #include<unistd.h>
  8 #include<stdlib.h>
  9 
 10 int main()
 11 {
 12   int max_cnt=0;
 13   pid_t id=fork();
 14   while(1)
 15   {
 16 
 17     if(id<0)
 18     {
 19  //这个代码是父进程在执行 因为fork创建失败没有子进程执行
 20     printf("fork error:man_cnt=%d\n",max_cnt);
 21     break;
 22     }
 23     else if(id==0)
 24     {
 25       //child
 26       while(1)
 27       {
 28           sleep(1);
 29       }
 30     }
 31     else
 32     {
 33       //father 
 34       printf("max_cnt:%d\n",max_cnt);
 35     }
 36     max_cnt++;
 37   }
 38 }
 39 
 40 //max_cnt是父子共享的
 41 //但是写时拷贝对父进程是不影响的
 42 //写时拷贝改的一直是父进程的
 43 
 44 //子进程一直不退出 fork失败后父进程退出
 45 //子进程变成孤儿进程                             

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

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

相关文章

GEE:均值滤波

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine(GEE)平台上,进行均值滤波操作的代码框架、核心函数和多种卷积核。 并分别以林地区域和农田区域为试验区,以NDVI图像为例。结果如下图所示, 文章目录 一、均值滤波二、完整代码三、代码链接一、均值滤波 均值滤…

Docker常用进本命令【必备基本功】

docker常用命令 1.帮助命令 1.查看当前docker 版本 docker version2.查看docker的详细信息 docker info3.docker的帮助命令 docker --help2.镜像命令 镜像命令说明docker images列出本地主机的镜像docker search 镜像名称从docker HUB上搜索镜像docker pull 镜像名称从…

ScyllaDB 基础入门

简介 ScyllaDB 是一种开源的 NoSQL 数据库&#xff0c;它提供了高性能、低延迟的数据处理能力&#xff0c;同时保持了与 Apache Cassandra 高度的兼容性。ScyllaDB 使用了一种名为 “Seastar” 的高效并行编程框架&#xff0c;并采用了 C 进行开发&#xff0c;因此它能够充分利…

Linux 进程状态

操作系统学科的进程状态 新建态&#xff1a;刚刚创建的进程&#xff0c; 操作系统还未把它加入可执行进程组&#xff0c; 它通常是进程控制块已经创建但还未加载到内存中的新进程。就绪态&#xff1a;进程做好了准备&#xff0c;只要有机会就开始执行。阻塞态&#xff1a;进程在…

【富文本编辑器】原生JS使用WangEditor和vue上传图片前后端demo

【富文本编辑器】原生JS使用WangEditor上传图片前后端demo 第一步 HTML 第二步 初始化WangEditor与图片上传回调函数 第三步 后端返回数据体封装 第四步 后端接口上传图片&#xff0c;并返回图片地址 最近&#xff0c;我遇到了这样一个问题&#xff1a;因为我们的项目是基于…

网络和Linux网络_9(应用层和传输层_笔试选择题)

目录 一. 常见应用协议等等 1. 以下不是合法HTTP请求方法的是( ) 2. 文件传输使用的协议是&#xff08;&#xff09; 3. HTTP1.1的请求方法不包括&#xff1f;() 4. http状态码中&#xff0c;( )表示访问成功&#xff0c;( )表示坏请求&#xff0c;( )表示服务不可用。() …

【力扣206】反转链表

【力扣206】反转链表 一.题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1 &#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2 &#xff1a; 输入&#xff1a;head [1,2] 输出&#x…

物奇平台电容触摸功能调试

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 物奇平台电容触摸功能调试 1 修改按键驱动宏 2 编译生成wpk 文件,import 导入烧录文件。…

先遗忘后学习:基于参数计算的大模型知识更新

深度学习自然语言处理 原创作者&#xff1a;陈定纬编辑&#xff1a;cola 最近&#xff0c;大型语言模型&#xff08;LLMs&#xff09;展示了其令人惊叹的文本理解和生成能力。然而&#xff0c;即使是更为强大的LLMs&#xff0c;仍有可能从训练语料库中学到不正确的知识&#xf…

k8s安装学习环境

目录 环境准备 配置hosts 关闭防火墙 关闭交换分区 调整swappiness参数 关闭setlinux Ipv4转发 时钟同步 安装Docker 配置Yum源 安装 配置 启动 日志 安装k8s 配置Yum源 Master节点 安装 初始化 配置kubectl 部署CNI网络插件 Node节点 检查 环境准备 准…

LASSO vs GridSearchCV

LASSO VS GridSearchCV LASSO定义目的使用方法原理示例总结 GridSearchCV定义目的使用方法原理网格搜索&#xff08;Grid Search&#xff09;交叉验证&#xff08;Cross-Validation&#xff09;总结 示例总结 总结 LASSO 定义 LASSO&#xff08;Least Absolute Shrinkage and…

【ArcGIS Pro微课1000例】0040:ArcGIS Pro创建北极点、南极点

文章目录 一、创建北极点图层二、创建北极点三、不同投影系下北极点的位置一、创建北极点图层 选择一个数据库,在上面右键→新建→要素类。 输入名称:北极点。 空间参考:WGS 1984 点击创建。 二、创建北极点 在编辑选项卡下,点击【创建】。 在创建要素窗口中,点击北极点…

【RT-DETR改进】InnerIoU思想结合传统 EIoU、SIoU、WIoU损失思想(小目标涨点效果明显)

论文地址&#xff1a;官方Inner-IoU论文地址点击即可跳转 官方代码地址&#xff1a;官方代码地址-官方只放出了两种结合方式CIoU、SIoU 本位改进地址&#xff1a; 文末提供完整代码块-包括InnerEIoU、InnerCIoU、InnerDIoU等七种结合方式和其AlphaIoU变种结合起来可以达到二十…

轻盈悦耳的运动型气传导耳机,还有条夜跑灯,哈氪聆光体验

我平时出门不管是散步、骑行&#xff0c;还是坐公交的时候&#xff0c;都喜欢戴上耳机听音乐&#xff0c;这可以让我放松心情。现在市面上的耳机还是以真无线为主&#xff0c;选择虽多&#xff0c;但不适合户外使用&#xff0c;听不见外界的声音&#xff0c;运动时还容易脱落&a…

牛客在线编程(SQL大厂面试真题)

1.各个视频的平均完播率_牛客题霸_牛客网 ROP TABLE IF EXISTS tb_user_video_log, tb_video_info; CREATE TABLE tb_user_video_log (id INT PRIMARY KEY AUTO_INCREMENT COMMENT 自增ID,uid INT NOT NULL COMMENT 用户ID,video_id INT NOT NULL COMMENT 视频ID,start_time d…

链表【1】

文章目录 &#x1f348;2. 两数相加&#x1f34c;1. 题目&#x1f34f;2. 算法原理&#x1f353;3. 代码实现 &#x1f349;445. 两数相加 II&#x1f34d;1. 题目&#x1f350;2. 算法原理&#x1fad0;3. 代码实现 &#x1f348;2. 两数相加 &#x1f34c;1. 题目 题目链接&…

【数据结构高阶】AVL树

上期博客我们讲解了set/multiset/map/multimap的使用&#xff0c;下面我们来深入到底层&#xff0c;讲解其内部结构&#xff1a; 目录 一、AVL树的概念 二、AVL树的实现 2.1 节点的定义 2.2 数据的插入 2.2.1 平衡因子的调整 2.2.1.1 调整平衡因子的规律 2.2.2 子树的旋…

对一个多维随机变量作为线性变换以后的协方差矩阵

假设是一个n维的随机变量&#xff0c;它的协方差矩阵 对做线性变换&#xff0c;其中是一个矩阵&#xff08;当然也可以是一个标量&#xff09;&#xff0c;的协方差矩阵 证明如下&#xff1a; 将代入&#xff0c;得

git如何关联克隆远程仓库

一、添加远程仓库 之前我们仅仅是在本地创建了一个Git本地仓库&#xff0c;这里我们再在GitHub创建一个Git远程仓库&#xff0c;并且让这两个仓库进行远程同步&#xff0c;这样&#xff0c;GitHub上的仓库既可以作为备份&#xff0c;又可以让其他人通过该仓库来协作开发。 1.…

【无标题】我们只能用成功来摧毁我们,原来的自己只会破败自己的事情。

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…
最新文章