进程创建进程终止进程等待

news2024/9/24 11:23:18

目录

    • 前言
    • 一、进程创建
      • 1.fork()函数
        • (1)fork()函数的基本认识
        • 进程调用fork()函数之后,控制权转移到内核中的fork()代码之后,内核做了啥?
        • (2)实验:使用fork()函数创建进程
        • (3)实验:验证子进程的存在
        • (4)实验:演示使用fork()函数创建进程失败的现象
        • (5)关于fork()函数需要知道的点
        • (6)fork()函数执行之后,操作系统做了什么?
      • 2.写时拷贝
        • (1)写时拷贝的具体过程分析
        • (2)为什么要采取写时拷贝?创建子进程的时候就将数据分开不行吗?
        • (3)写时拷贝的意义
    • 二、进程终止
      • 1.main函数的返回值
      • 2. 进程终止的三种常见情况
      • 3.进程终止的常见做法
      • 4.exit()和_exit()的使用
        • (1)实验:验证exit()和_exit()的区别
        • (2)exit()和_exit()的区别
      • 5.关于终止,内核做了啥?
    • 三、进程等待
      • 1.进程等待的原因
      • 2.进程等待的方法
        • (1)wait()函数
        • (2)waitpid()函数
    • 总结

前言

在这篇文章中我们学习了进程创建,进程终止,进程等待三个内容,首先学习使用fork()函数来创建一个子进程和创建子进程之后使用写时拷贝技术解决父子进程数据问题,然后就是进程终止和进程等待,进程终止主要是讲了使用exit()函数来终止一个进程,进程等待主要是为了解决僵尸进程的问题,回收僵尸进程的退出信息

一、进程创建

1.fork()函数

(1)fork()函数的基本认识

  1. 使用man手册查看fork()函数的使用方法
    在这里插入图片描述
  2. 基本使用方法pid_t fork(void);
  3. 返回值
  • 如果创建成功:给父进程返回子进程的pid,给子进程返回0
  • 如果创建失败,给父进程返回-1
  1. 功能:父进程调用fork()函数创建一个子进程

进程调用fork()函数之后,控制权转移到内核中的fork()代码之后,内核做了啥?

  1. 分配内存块和内核数据结构给子进程
  2. 将父进程部分数据结构内容拷贝给子进程
  3. 添加子进程到系统的进程列表
  4. fork()返回之后,开始调度器调度

(2)实验:使用fork()函数创建进程

  • 构建项目
  1. 创建fork.c和makefile文件
    在这里插入图片描述
    在这里插入图片描述
  2. 实验结果
    在这里插入图片描述

(3)实验:验证子进程的存在

  1. 构建项目
    在这里插入图片描述
    在这里插入图片描述
  2. 实验结果
    在这里插入图片描述
    显然就是两个进程去调用printf函数,从而出现两条结果
    在这里插入图片描述

(4)实验:演示使用fork()函数创建进程失败的现象

  1. 构建项目
  • 创建fork_err项目(其中包含fork.c文件和makefile文件)
    在这里插入图片描述
    在这里插入图片描述
  1. 编译形成可执行程序并查看实验结果
    在这里插入图片描述
  • fork()函数创建进程失败的原因
  1. 系统中有太多的进程
  2. 实际用户的进程数超过了限制
  3. 内存不够

(5)关于fork()函数需要知道的点

  1. 共享代码:fork()函数创建子进程之后,父子进程共享同一份代码,代码一般都是只读的,所以父子进程无法对代码做出修改,但是数据可能会被修改,因此,在父子进程没有修改数据的情况下,父子进程可以共享同一份数据,但是如果父子进程其中一者对数据做出修改,那么此时将会发生写时拷贝
  2. eip程序计数器(pc指针):在CPU中有一个寄存器叫程序计数器(eip),这个寄存器可以保存当前正在执行的指令的下一条指令,当创建子进程之后,程序计数器会将其内容拷贝给子进程,因此,子进程便知道父进程上次执行到哪个地方,从而便从eip指向的地方继续向下执行,这就是子进程创建之后是从fork()函数之后的代码继续执行,而不是从头开始执行的原因

(6)fork()函数执行之后,操作系统做了什么?

我们都知道,进程是由内核的进程数据结构进程的代码和数据组成的,内核的数据结构我们现在所知道的有两个:task_struct+mm_struct,所以此过程操作系统会创建子进程的内核数据结构和页表,然后子进程的代码继承自父进程,数据通过写时拷贝的方式进行共享

2.写时拷贝

写时拷贝是维护进程独立性的一个非常重要的手段,其通常是指在系统识别到有人要更改数据时,会在系统的内存中为该数据再开辟一个空间,然后将该数据的值拷贝过去,最后在新空间上进行修改,从而实现两个进程的数据的分离,两个进程对该数据的修改互不影响,从而维护了进程的独立性

(1)写时拷贝的具体过程分析

  • 修改内容前
    在这里插入图片描述
    父进程和子进程使用的代码段是只读的,因此代码段的内容进行共享即可,在修改之前,因为没有进程对数据内容做修改,因此,此时父子进程共享同一份数据(映射的物理空间是同一块空间)
  • 修改数据
    在这里插入图片描述
    当操作系统识别到子进程想要修改该数据,便在内存中的另一个地方为该数据再分配一块新的空间,这个空间只属于子进程的,此时再将该数据原来的值拷贝放到该空间,然后再在该空间对该数据进行修改,同时操作系统会更新子进程中的页表映射关系修改的主要该数据映射的物理空间,虚拟空间不需要做修改物理地址修改为后面分配的物理地址,此时父子进程对该数据的虚拟地址是一样的,但是通过页表映射之后的物理地址是不一样的,属于两块不同的空间

(2)为什么要采取写时拷贝?创建子进程的时候就将数据分开不行吗?

  1. 父进程的数据子进程不一定都要用到,即使都要用到也不一定都要写入(修改),这样就会有浪费空间的嫌疑
  2. 最理想的情况是只有被父子进程修改的数据才需要进行分离拷贝,不需要修改的数据共享即可
  3. 如果在fork的时候就无脑进行拷贝数据分离给子进程会增加fork的成本(内存和时间上)

(3)写时拷贝的意义

写时拷贝是一种延迟拷贝的策略,只有真正使用的时候才进行拷贝分离,暂时不使用但是想要的空间不会进行写时拷贝,此时该空间可以先分配给其他进程进行使用,这样就变向提高了内存的利用率

二、进程终止

1.main函数的返回值

在我们的C语言或者C++语言中,我们通常会写main函数,这个main函数我们知道是程序的入口,通常我们会在最后写上return 0;
在这里插入图片描述
那么这个return 0;中的0到底是什么意思?
其实,这个0代表的是进程的退出码,0表示的是进程正常结束,运行结果正确非零表示进程运行结束,运行结果不正确,其中退出码的非零就是代表结果运行不正确的原因,退出码是返回给当前进程的父进程进行接收的

  • 怎么查看进程的退出码呢?
    使用echo $?命令
    演示:
    在这里插入图片描述
    使用echo $?查看退出码
    在这里插入图片描述
    此时该进程的父进程是bash进程,而echo $?表示的是bash最近一次执行完毕对应进程的退出码
  • 查看1-100对应的错误(退出)信息
  1. 源代码
    在这里插入图片描述
  2. 运行结果
    在这里插入图片描述

2. 进程终止的三种常见情况

  • 代码跑完,运行结果正确
  • 代码跑完,运行结果不正确
  • 代码没跑完,异常退出

3.进程终止的常见做法

  • 在main函数中使用reutrn语句
    main函数是程序的入口,在main函数中使用return语句表示程序的结束,此时需要注意的是,在非main函数中使用return语句不代表程序的结束,只能代表函数的调用结束
    演示:
  1. 源代码
    在这里插入图片描述
  2. 实验结果
    在这里插入图片描述
  • 在程序中的任何地方使用exit()函数
    exit()函数表示终止程序,在程序的任何位置调用exit()函数都可以使程序马上停下来
    演示:
  1. 源代码
    在这里插入图片描述
  2. 实验结果

在这里插入图片描述

4.exit()和_exit()的使用

  • 使用man手册查看:man 2 exit
    在这里插入图片描述

(1)实验:验证exit()和_exit()的区别

  1. 使用exit()
  • 源代码
    在这里插入图片描述
  • 实验结果
    在这里插入图片描述
  1. 使用_exit()
  • 源代码
    在这里插入图片描述
  • 实验结果
    在这里插入图片描述
    结论:我们知道,我们使用printf语句进行打印的时候,打印的内容首先是会暂存在缓冲区,不会马上就刷新到外设上的,上面的两个实验分别使用exit()函数和_exit()函数操作这段代码,结果我们发现,当我们使用exit()函数的时候,缓冲区的东西能够刷新到显示屏上,而当我们使用_exit()函数的时候,缓冲区的内容无法刷新到显示屏上,从而我们会发现,exit()函数在终止程序的时候会刷新缓冲区,_exit()函数在终止程序的时候不会刷新缓冲区

(2)exit()和_exit()的区别

在这里插入图片描述
通过上图我们会发现,调用_exit()函数时,只会直接终止程序,不会做任何事情,调用exit()时,会执行用户定义的清理函数和刷新缓冲区和关闭对应的流,因此,一般情况下,我们常用的是exit()函数

5.关于终止,内核做了啥?

我们知道,一个进程是由自己的内核数据结构和进程代码和数据组成的,当一个进程退出的时候,首先自己的进程状态会变成Z状态,也就是所谓的僵尸状态,此时需要等其父进程对其进程回收,由终止我们知道其需要给其父进程返回退出码,这个进程的状态马上变成X状态,其父进程的相关代码会回收(释放)其数据和相关代码,因为当该进程终止的时候,其数据和代码已经没有任何意义了,但是需要注意的是管理这个进程的内核数据结构可能不会被释放,这个内核数据结构在系统内存充足的时候会被加入一个链表,这个链表叫做废弃数据结构链表,专门收集终止的进程的内核数据结构,也叫数据结构缓冲池,或者slap分派器

三、进程等待

1.进程等待的原因

  1. 解决进程僵尸的问题
    一个进程退出的时候会进入僵尸状态,处于僵尸状态的进程无法再次被杀掉,但是其自身的代码和数据以及相关的内核数据结构仍然会占用系统的内存资源,如果进程长期处于僵尸状态,则会长期占用系统内存中的相关资源进而导致内存泄露
  2. 获取进程的退出信息(退出码和异常信号)
    我们学习进程终止的时候知道,进程在退出的时候会有相关的退出码或者异常信号,一个进程创建了子进程是为了完成相关事情的,一个进程在其终止时理应当告诉其父进程自己的工作完成地怎么样了,是成功还是失败,进程就是通过退出码或者异常信号告诉其父进程这些信息的

2.进程等待的方法

(1)wait()函数

  • 使用man手册查看wait()的使用方法
    在这里插入图片描述
    在这里插入图片描述
    wait()函数有一个参数是int* status;当我们的参数传成NULL的时候,那么这个调用这个函数的进程就可以等待任何进程了,wait函数的返回值是等待的进程的pid,如果等待成功,那么会返回等待进程的Pid,如果等待失败,则会返回-1
    上面的代码的逻辑很简单:首先使用原来的进程创建一个子进程,然后我们明确,在成功创建子进程后两个进程是同时存在的,同时在执行程序中的代码,其意思就是要在子进程被杀死的时候父进程要调用wait函数来等待子进程,那么当子进程被杀死的时候,子进程的状态马上就会变成僵尸状态,那么此时父进程就会回收子进程的退出信息,回收之后,子进程就会消失,父进程正常执行其后面的代码,直至退出
    在这里插入图片描述

(2)waitpid()函数

  • 使用man手册查看使用方法
    在这里插入图片描述

  • 返回值:如果返回值的结果大于0,则说明等待成功,返回值为等待的进程的pid,如果返回值的结果小于0,则说明等待失败

  • 参数pid_t pid:等待的进程的pid

  • 参数int status*:这个参数是一个输出型参数,可以将系统中的一些数据带出来,通常包含等待进程的退出码或者是异常信号

  • 参数int option:现在先写0,表示阻塞等待,现在先不考虑非阻塞等待

  • waitpid()函数的使用

  1. 构建项目
  • 创建test.c和makefile文件
    在这里插入图片描述
    在这里插入图片描述
  1. 实验结果
    在这里插入图片描述
    实验思路:利用一个进程创建一个子进程,这个实验中,因为在子进程中有睡眠1秒,所以在子进程正常运行的过程中,子进程的状态为S状态,此时父进程正在等待子进程被杀掉,当子进程被kill命令杀掉的时候,那么父进程此时就会回收子进程的退出信息,子进程再正常释放,父进程继续执行后面的代码

注意:关于子进程的退出码和异常信号现在先记住写法:退出码就是(status>>8)&0xFF,异常信号是status&0x7F

总结

在这篇文章中首先我们学习了使用fork()函数来创建一个子进程和写时拷贝技术解决父子进程数据问题,然后就是进程终止和进程等待,进程终止主要是讲了使用exit()函数来终止一个进程,进程等待主要是为了解决僵尸进程的问题,回收僵尸进程的退出信息

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

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

相关文章

跨境电商卖家必知的【圣诞节营销】终极指南(一)

关键词:圣诞节营销、跨境电商卖家 不知不觉又到了年底,而对于跨境电商来说也是非常重要的一段促销时期,也许您已经制定了相关的圣诞节营销大促,但今天我们还是想告诉您一些2022年非常棒的销的创意想法,希望能帮助您提升…

Spring Cloud Alibaba(四)

openFeign配置日志 一、openFeign的日志级别: NONE:不记录日志 (默认). BASIC:只记录请求方法、url、响应状态码和执行时间。 HEADERS:在basic的基础上,增加请求和响应头 FULL:记录请求和响应的头、body…

PyTorch搭建RNN联合嵌入模型(LSTM GRU)实现视觉问答(VQA)实战(超详细 附数据集和源码)

需要源码和数据集请点赞关注收藏后评论区留言私信~~~ 一、视觉问题简介 视觉问答(VQA)是一种同时设计计算机视觉和自然语言处理的学习任务。简单来说,VQA就是对给定的图片进行问答,一个VQA系统以一张图片和一个关于这张图片形式自…

用HTML+CSS+JS写的切水果小游戏它来了

前言 切水果游戏曾经是一款风靡手机的休闲游戏,今天要分享的就是一款网页版的切水果游戏, 由HTMLCSSJS实现,虽然功能和原版的相差太大,但基本的功能具备,效果逼真。感兴趣的小伙伴可收藏学习(完整源码在文…

Heterogeneous Parallel Programming 异构并行编程 - UIUC伊利诺伊大学(持续更新)

Lecture 11.2 Introduction to Heterogeneous异构1.3 Portability and Scalability1.4 Introduction to CUDA 数据并行化 and 执行模型1.5 Introduction to CUDA 内存模型 and 基本函数API1.6 Introduction to CUDA Kernel-based SPMD1.7 更高维的Grid的Kernel-based SPMD例子1…

Linux的基本协议与他的堂兄堂弟

14天学习训练营导师课程: 互联网老辛《 符合学习规律的超详细linux实战快速入门》 努力是为了不平庸~ 学习有些时候是枯燥的,但收获的快乐是加倍的,欢迎记录下你的那些努力时刻(学习知识点/题解/项目实操/遇到的bug/等等&#xf…

教程一 在Go使用JavaScript、HTML和CSS构建Windows、Linux、MacOSX跨平台的桌面应用

Energy是Go语言使用JavaScript、HTML和CSS构建跨平台的桌面应用程序可用于构建跨平台的桌面应用内嵌 Chromium CEF 二进制 环境安装 Energy 命令行工具 使用命令行工具自动安装Energy框架的所有依赖(CEF),支持Window、Linux、MacOSX 安装过程从网络下载CEF和Energy…

二、vue基础入门

一、vue简介 1.1、什么是vue 官方给出的概念:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的前端框架。 1.2、vue的特性 vue框架的特性,主要体现在如下两方面: 数据驱动视图双向数据绑定 1.2.1、数据驱动视图 在…

高灵敏度艾美捷小鼠肿瘤坏死因子α-ELISpot试剂盒

肿瘤坏死因子-a(TNF-a)由许多不同的细胞类型产生,例如单核细胞,巨噬细胞,T细胞和B细胞。在TNF-a的许多作用中,有针对细菌感染,细胞生长调节,免疫系统调节和参与败血症性休克的保护。…

现代气象仪器 | 太阳辐射测量

南京信息工程大学 实验(实习)报告 实验(实习)名称 现代气象仪器 实验(实习)日期 10.28 得分 指导老师 学院 电信院 专业 电子信息工程 年级 2020 班次 4 姓名 学号 20208327 实验…

万字博客带你全面剖析Spring的依赖注入

1.写在前面 前面的博客我们已经写了Spring的依赖查找,这篇博客我们来了解写Spring的依赖注入。 2.依赖注入的模式和类型 手动模式 - 配置或者编程的方式, 提前安排注入规则 XML 资源配置元信息Java 注解配置元信息API 配置元信息 自动模式 - 实现方…

华为机试 - 最大括号深度

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 现有一字符串仅由 ‘(‘,’)’,{‘,’}’,[‘,’]’六种括号组成。 若字符串满足以下条件之一,则为无效字符串: ①…

【MySQL】拿来即用 —— MySQL中的数据类型

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ MySQL数据类型⚪熟悉SQL一、MySQL数据类型总结…

设备树和设备树语法

设备树 驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中。许多硬件设备信息可以直 接通过它传递给 Linux,而不需要在内核中堆积大量的冗余代码。 设备树,将这个词分开就是“设备”和“树”,描述设备树的文…

【计算机毕业设计】22.毕业设计选题系统ssm源码

一、系统截图(需要演示视频可以私聊) 引言 近年来,电子商务发展的愈趋成熟使得人们的消费方式以及消费观念发生巨大改变,网上竞拍的拍卖模式随之发展起来。大学拍卖网旨在为湘大学生提供一个线上拍卖的交易平台。平台展示的商品大…

【American English】美式发音,英语发音,美国音音标列表及发音

首先声明,网上各种英式发音和美式发音的教程,而我的目的是寻找美式发音。但是自己现在也是在不断地找寻中,所以资料找错了请莫怪。另外,资料顺序采用部分倒叙,不喜请勿吐槽。 文章目录发音示意图49. [](https://www.bi…

百度地图有感

以前总认为坚持会让我们变强大,但是长大后发现,让我们强大的,是放下。 生活也许就是这样,多一分经验便少一分幻想,以实际的愉快平衡现实的痛苦。 百度地图开放平台 百度地图入门指南 百度地图开发指南 百度地图API文…

性早熟和微生物群:性激素-肠道菌群轴的作用

谷禾健康 肠道菌群 & 性激素 青春期是生命的一个关键阶段,与性成熟相关的生理变化有关,是一个受多种内分泌和遗传控制调控的复杂过程。 青春期发育可以在适当的时候,早熟或延迟。 未经治疗的性早熟的孩子通常不会达到成年身高的全部潜力。…

Activity的最佳实践

文章目录Activity的最佳实践知晓当前是在哪一个Activiy随时随地退出程序启动Activity的最佳写法Activity的最佳实践 知晓当前是在哪一个Activiy 创建一个BaseActivity类,继承AppCompatActivity类.重写onCreate方法 open class BaseActivity : AppCompatActivity() {override…

xilinx PL测 DP 点屏 /接收(二)--RX

环境: a)硬件:官方ZCU106开发板 , tb-fmch-vfmc-dp子卡。 b)软件:vivado2021.1,vitis2021.1,裸机程序。 1、官方例程: 2、DP RX IP : 3、DP RX寄存器: 4、时钟: 5、像素&…