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

进程创建与退出的原理

目录

一、task_struct的创建与链接

二、内核处理进程退出的主要步骤    


        在所有的操作系统中,都遵循着一个“先描述,后管理”的原则。所谓描述就是把一个抽象的状态(如硬件资源、运行状态等)用一个结构体来表示,以后只要状态发生了改变就必须先修改这个结构体中对应的成员;而管理则是说有着许许多多的硬件状态,不能孤立的存在而应该放在一个统一的容器中存放,想要查询、修改哪一个硬件只需要到这个“档案室”中找到其结构体,并进行修改。

        本篇文章我们只讨论进程的描述结构体,即进程控制块(Process Control Block),在不同的操作系统中PCB有着不同的叫法,而在Linux中我们称之为task_struct。

一、task_struct的创建与链接

        既然我们说所有的东西都要先描述再管理,那么进程也不例外。当使用fork函数创建一个进程的时候,操作系统内核首先就会创建一个task_struct结构体。这个结构体由于需要操作系统管理,则必定是在内核空间中的。即全局的进程链表。

        当task_struct已经被链入到内核的全局链表中了,则会开始填充骨肉。

最后会把该task_struct链入运行队列中,让调度器能够管理其运行。

二、内核处理进程退出的主要步骤    

        进程退出通常分为正常退出(进程本身通过return或exit函数退出)和异常退出(运行时收到了外部的终止信号、或运行错误)

  • (1)释放资源
    • 内存资源:进程占用的用户空间内存(包括堆、栈、数据段等 )会被释放。内核会根据进程task_struct中记录的内存描述符(mm_struct )信息,回收分配给该进程的虚拟内存区域和对应的物理内存页框。如果存在共享内存,会检查引用计数,当引用计数为 0 时,释放共享内存资源。
    • 文件描述符:关闭进程打开的所有文件描述符。内核会遍历进程task_struct中的文件描述符表,调用相应的文件系统操作来关闭文件,释放相关的文件资源,如文件锁、缓存等 。
    • 其他资源:例如进程创建的管道、信号量、消息队列等进程间通信资源,也会根据情况进行释放或清理。
  • (2)更新父进程信息子进程需要向父进程报告自己的退出状态。如果父进程调用了waitwaitpid函数等待子进程结束,那么父进程会获取子进程的退出状态。同时,内核会在父进程的task_struct中更新子进程的相关信息,比如从父进程记录子进程的链表中移除该子进程节点 。
  • (3)从运行队列移除如果进程在退出前处于运行队列(就绪态 ),内核会将其task_struct从运行队列中移除。以 Linux 内核的 CFS(完全公平调度器 )为例,会操作运行队列对应的红黑树,将代表该进程的调度实体(sched_entity ,在task_struct中 )从红黑树中删除,这样调度器就不会再调度该进程运行。
  • (4)从等待队列移除若进程处于阻塞态,在等待某个事件(如 I/O 操作完成、信号量获取等 ),它会在相应的等待队列中。内核会找到该进程所在的等待队列,将其task_struct从队列中移除,避免后续该进程被错误唤醒。
  • (5)从全局进程链表移除Linux 内核使用双向循环链表管理所有进程,以init_task作为链表头。当进程退出时,会将其task_struct中的tasks节点(用于连接到全局进程链表的节点 )从链表中摘除,具体操作是修改前后节点的nextprev指针,使链表中不再包含该进程的task_struct 。
  • 6)处理僵尸状态(Zombie State):如果父进程没有调用waitwaitpid来获取子进程的退出状态,子进程会进入僵尸状态,此时子进程的task_struct不会立即被释放,而是会保留在内存中,等待父进程获取其退出状态。不过,即使处于僵尸态,它也已经从运行队列、等待队列等功能性队列中移除,只是还在全局进程链表中,直到父进程调用wait系列函数后,内核才会彻底释放该task_struct占用的内存。

        值得注意的是:当一个进程退出后,会被标记为僵尸状态,且从运行队列、阻塞队列中移除。但是并未移出全局进程链表以及父进程的子进程链表,只有当父进程使用wait或waitpid后才会在子进程链表中找到该pcb,获取退出信息后才销毁。


文章转载自:
http://asteraceous.aaladrg.cn
http://actinism.aaladrg.cn
http://chowmatistic.aaladrg.cn
http://bacchius.aaladrg.cn
http://bismuth.aaladrg.cn
http://bronchobuster.aaladrg.cn
http://beerpull.aaladrg.cn
http://chapeau.aaladrg.cn
http://antiperspirant.aaladrg.cn
http://candidly.aaladrg.cn
http://chatelet.aaladrg.cn
http://babbitt.aaladrg.cn
http://authenticator.aaladrg.cn
http://casualize.aaladrg.cn
http://albescent.aaladrg.cn
http://absolvable.aaladrg.cn
http://cachou.aaladrg.cn
http://alkermes.aaladrg.cn
http://byland.aaladrg.cn
http://acclimatize.aaladrg.cn
http://biologist.aaladrg.cn
http://carthage.aaladrg.cn
http://bosomy.aaladrg.cn
http://banjo.aaladrg.cn
http://assonance.aaladrg.cn
http://asafoetida.aaladrg.cn
http://calycoideous.aaladrg.cn
http://bodega.aaladrg.cn
http://astigmatoscopy.aaladrg.cn
http://carnivalesque.aaladrg.cn
http://www.dtcms.com/a/280960.html

相关文章:

  • 5.数据归一化
  • Paimon 删除向量
  • 元宇宙经济:虚实交融下的数字文明新范式
  • Python 函数:从“是什么”到“怎么用”的完整指南
  • 【Linux驱动-快速回顾】一文快速理解GIC内部寄存器对中断的控制
  • Claude技术全景解读:从安全聊天机器人到自主智能体的演进之路
  • 数据结构自学Day7-- 二叉树
  • 项目总体框架(servlet+axios+Mybatis)
  • ue4 houdini pivot painter 学习笔记
  • 可微分3D高斯溅射(3DGS)在医学图像三维重建中的应用
  • OpenCV 对数变换函数logTransform()
  • ubuntu22.04 软创建 RAID1 与配置流程
  • pytest快速上手指南【pytest】
  • LED 照明应用提供高性价比方案?会是你的首选吗?
  • C++ 中两个类之间的通信方式
  • labview关于OOP
  • labview生成exe应用程序常见问题
  • Java行为型模式---责任链模式
  • redis集群的部署
  • 渭河SQL题库-- 来自渭河数据分析
  • JavaScript与Vue:现代前端开发的完美组合
  • King’s LIMS:实验室数字化转型的智能高效之选
  • AWS S3事件通知实战:从配置到生产的完整指南
  • 云蝠智能赋能呼入场景——重构企业电话服务
  • JVM——为什么Java8移除了永久代(PermGen)并引入了元空间(Metaspace)?
  • 订单初版—7.支付和履约实现的重构文档
  • 域名备案是否可以加急
  • DirectX12(D3D12)基础教程九 间接绘制
  • Dynadot邮箱工具指南(十二):删除域名邮箱
  • 学习软件测试的第十六天