当前课程知识点:操作系统 > 第十二讲 进程控制 > 12.4 进程等待与退出 > 12.4 进程等待与退出
下面我们来介绍
进程的等待和退出
等待和退出呢实际上
是父子进程之间的一种交互
完成子进程的资源回收
那首先第一个是等待
那个wait()这个系统调用呢
可以用于父进程等待子进程的结束
那具体说起来呢
子进程通过exic()
向父进程返回一个值
父进程呢通过wait()
接受并处理这个返回值
那这时候就有一个问题说
这两个到底谁先谁后
wait父进程先等待
还是子进程先做exit()
这两种情况的不同呢
会导致它下面的处理呢
会有一些区别
wait执行的调用呢
在我们这里就是
如果有子进程存活
也就是说父进程创建的子进程
还有子进程
那这时候呢父进程进入等待状态
等待子进程的返回结果
好那等待的时候呢
这就相当于是wait
父进程先执行wait
等到子进程执行的时候呢
它执行exit ()
这是exit ()是在wait之后执行的
好那么这时候呢
子进程的exit ()退出唤醒父进程
父进程呢就由等待状态
回到就绪状态
等它得到CPU的使用权
可以执行的时候
那么父进程就处理
子进程的返回的这个返回值
这是wait在前exit ()在后的情况
如果不是这样那就有一种情况
就是有僵尸子进程等待
这指什么意思呢
就是子进程先执行exit ()
那这时候说它返回一个值
等待父进程的处理
那这时候呢exit ()在前
好在这个时候如果子进程
还一直处在这个等待的状态
在这里等待父进程的处理
那么这时候呢
父进程的wait就直接返回
如果有多个的话
就从其中一个返回它的值
如果没有子进程在
有可能我一个进程在执行的时候
它执行了wait
实际上它干脆就没有子进程
或者说子进程已经结束了
好那这时候呢它就直接返回
这是呢wait的功能
那接下来说exit
在这里头呢它叫有序退出
它指的是什么意思呢
我执行这个exit
这时候呢
这个进程呢就会在这个
系统调用里头
就会进行资源的回收
那具体的功能是这样的
首先第一个是我们刚才说到的
调用参数返回给父进程结果那exit
然后父进程呢可以拿到它这个结果
比如说我们在做一个编译
你的编译是否成功
这个编译成功之后呢我回复是0
如果不成功我回复错误码
这样的话我下面的
调用编译的这个进程
它依据你编译的结果
来决定后续怎么做
这是它第一项功能
然后第二部分功能是资源回收
你比如说我们占用的
各种资源的回收
占用的打开的文件
分配的内存和创建的
内核相关数据结构
然后检查父进程是否还存活
刚才我们说父进程会检查子进程
子进程也会检查父进程
子进程是执行exit的时候
检查父进程
父进程是在执行wait的时候
检查子进程
好如果这个子进程在exit的时候
检查父进程如果父进程是存活的
那么也就是这时候呢
子进程就保留一个状态
它自己进入僵尸状态
也就是我们退出状态
然后等待父进程对它结果做处理
好如果说没有
也就相当于创建完子进程之后
父进程已经结束了
那么这时候呢它就直接
释放相应的数据结构并且进程结束
好那在这儿呢
同时这个检查完之后会清理
所有的处于等待状态的僵尸进程
好那么这样的话
这个exit退出实际上这是
把进程占用的所有的资源
包括这里头申请了
并没有显式释放的
它都会给它释放掉
这是退出
我们先来看wait
这是wait的实现
那么我们先看有哪些函数会来调
那各种平台上的sys_wait()会到这儿来
然后它在这里头呢
做的工作是在这里头do_exit()
实际上是子进程的收尾工作
然后把它放到队列里头去
schedule()在这个地方
是把它放到队列里头去
好我们也可以通过它的流程图来看
那在这个地方呢实际上就是说
我们把当前进程改成了sleeping的状态
这样的话它就变成阻塞状态了
那也就是我们找到了wait()里头
它是如何进到阻塞状态的
在这儿呢你就可以看到相关的代码
这是最明显的标志
好接下来一个是do_exit()
这是它的实现
它实际上在这里呢
就是保存在这里头呢
是把它把这个进程给杀掉
do_exit()把一个进程或者一个线程关掉
那我们也可以通过
它的调用关系图来看它的执行情况
那也是各种平台上的exit()
最后到这个地方来
它在这里呢
最后都是到这个地方
来释放相关的这些数据结构
这是它的相关的工作
好我们仍然可以来看一下
在这里它做的主要工作都是在干啥
那在这儿呢前面的注释已经说了
它把它地址空间页表
存储的这一部分空间给释放掉
然后把自己的状态改成叫僵尸状态
同时唤醒它的父亲
也就是说如果是wait的话
在那边等着的那个
我们也可以来看看它的流程图
这是它最主要的工作
是关于存储的那一部分的处理
好在这个地方呢
最后这一步是最主要的
我们需要去wakeup_proc()唤醒
处于wait状态的父进程
好除此之外呢我们刚才讲到的
这几个创建加载等待退出
这四个系统调用之外
我们对进程控制
还有一些其它系统调用
比如说优先级控制
那在unix系统呢有一个nice系统调用
它完成对进程的初始优先级的设置
好在unix系统里头进程的优先级
会随着执行时间的延续而衰减
也就是说它的优先级是在不断变化的
这是对优先级的控制
然后还有一个呢
是对调试的支持
在我们目前ucore里头呢
你没有办法在ucore内部
调试你写的应用程序
原因在于在我们这里
这一部分支持还不好
实际上在标准的操作系统里头呢
unix里头它有叫ptrace
这个系统调用呢
完成一个进程对另一个进程的
执行过程的控制
这就有点像我们说的调试
我让一个被调试进程继续执行
在某处设置断点
检查它的内存和寄存器的状态
这是操作系统必须提供的一项功能
然后还有就是定时
我们前面说过sleep
它可以让进程在指定的时间
进入等待状态
然后时间到了它进入就绪状态
然后继续执行这是定时的功能
好到这个地方为止呢
我们就说清楚了
进程控制的几个相关系统调用
它们的实现和它们的功能
那把这些控制功能和我们前面
讲到的进程状态图进行一个联系
我们会看到这样一种情况
这是我们前面讲到过的
三状态进程模型里头
那核心的就绪运行等待
再加上创建和退出这五个状态
我们刚才执行的
说到那几个进程控制的系统调用呢
对这个状态呢都是会有影响的
我们看看它的影响在什么地方
首先是fork fork会有啥影响
fork会导致一个新的进程的创建
好创建在那里准备工作做完
fork准备好了放在就绪队列里头
的时候它就变成就绪了
好然后再有一个是wait
wait会什么 父进程执行wait
会导致父进程由运行状态
进入等待状态
好然后再有一个是exit 退出
退出会导致当前进程
由运行进入退出状态
同时子进程的exit
会导致由于wait进入等待状态的
父进程变成事件发生触发
导致它进入就绪状态
以便于它能再进行执行的时候
对子进程的返回的结果进行处理
那这时候我们还有一个啥没说加载
这个系统调用它在什么地方
实际上加载是你在执行过程当中的
一种状态
准确的来说
那大家可以通过代码
去阅读看看这里头
我在加载可执行文件的过程当中
它还有相应的状态变化
好那到这个地方呢
我们就说清楚了
操作系统当中的进程控制
那从进程的切换
再到跟进程控制相关的
创建加载等待退出
这样主要的这几个系统调用
那这是呢操作系统提供给
应用程序用的最频繁的
最主要的几个功能
好今天的课就上到这里下课
-0.1 Piazza讨论区
--html
-0.2 在线实验平台
--实验平台使用帮助
--平台使用帮助
-0.2在线实验平台
--Raw HTML
-1.1 课程概述
--视频
-第一讲 操作系统概述--练习
-1.2 教学安排
--视频
-1.3 什么是操作系统
--Video
-1.4 为什么学习操作系统,如何学习操作系统
--Video
-1.5 操作系统实例
--视频
-1.6 操作系统的演变
--视频
-1.7 操作系统结构
--视频
-2.1 前言和国内外现状
-2.2 OS实验目标
-2.3 8个OS实验概述
-2.4 实验环境搭建
-2.5 x86-32硬件介绍
-2.6 ucore部分编程技巧
-2.7 演示实验操作过程
--Q6
--Q7
--Q10
-3.1 BIOS
--3.1 BIOS
-3.2 系统启动流程
-3.3 中断、异常和系统调用比较
-第三讲 启动、中断、异常和系统调用--3.3 中断、异常和系统调用比较
-3.4 系统调用
--3.4 系统调用
-第三讲 启动、中断、异常和系统调用--3.4 系统调用
-3.5 系统调用示例
-3.6 ucore+系统调用代码
-4.1 启动顺序
--4.1 启动顺序
-4.2 C函数调用的实现
-4.3 GCC内联汇编
-4.4 x86中断处理过程
-4.5 练习一
--4.5 练习一
-4.6 练习二
--4.6 练习二
-4.7 练习三
--4.7 练习三
-4.8 练习四 练习五
-4.9 练习六
--4.9 练习六
-5.1 计算机体系结构和内存层次
-5.2 地址空间和地址生成
-5.3 连续内存分配
-5.4 碎片整理
--5.4 碎片整理
-5.5 伙伴系统
--5.5 伙伴系统
-第五讲 物理内存管理: 连续内存分配--5.6 练习
-6.1 非连续内存分配的需求背景
-6.2 段式存储管理
-- 6.2 段式存储管理
-6.3 页式存储管理
-6.4 页表概述
--6.4 页表概述
-6.5 快表和多级页表
-6.6 反置页表
--6.6 反置页表
-6.7 段页式存储管理
-第六讲 物理内存管理: 非连续内存分配--6.8 练习
-7.1 了解x86保护模式中的特权级
-第七讲 实验二 物理内存管理--7.1 了解x86保护模式中的特权级
-7.2 了解特权级切换过程
-第七讲 实验二 物理内存管理--7.2 了解特权级切换过程
-7.3 了解段/页表
-第七讲 实验二 物理内存管理--7.3 了解段/页表
-7.4 了解UCORE建立段/页表
-第七讲 实验二 物理内存管理--7.4 了解UCORE建立段/页表
-7.5 演示lab2实验环节
-8.1 虚拟存储的需求背景
-8.2 覆盖和交换
-8.3 局部性原理
-8.4 虚拟存储概念
-8.5 虚拟页式存储
-8.6 缺页异常
--8.6 缺页异常
-9.1 页面置换算法的概念
-9.2 最优算法、先进先出算法和最近最久未使用算法
-第九讲 页面置换算法--9.2 最优算法、先进先出算法和最近最久未使用算法
-9.3 时钟置换算法和最不常用算法
-第九讲 页面置换算法--9.3 时钟置换算法和最不常用算法
-9.4 Belady现象和局部置换算法比较
-第九讲 页面置换算法--9.4 Belady现象和局部置换算法比较
-9.5 工作集置换算法
-第九讲 页面置换算法--9.5 工作集置换算法
-9.6 缺页率置换算法
-第九讲 页面置换算法--9.6 缺页率置换算法
-9.7 抖动和负载控制
-10.1 实验目标:虚存管理
-第十讲 实验三 虚拟内存管理--10.1 实验目标:虚存管理
-10.2 回顾历史和了解当下
-第十讲 实验三 虚拟内存管理--10.2 回顾历史和了解当下
-10.3 处理流程、关键数据结构和功能
-第十讲 实验三 虚拟内存管理--10.3 处理流程、关键数据结构和功能
-10.4 页访问异常
-第十讲 实验三 虚拟内存管理--10.4 页访问异常
-10.5 页换入换出机制
-第十讲 实验三 虚拟内存管理--10.5 页换入换出机制
-11.1 进程的概念
-第十一讲 进程和线程--11.1 进程的概念
-11.2 进程控制块
-第十一讲 进程和线程--11.2 进程控制块
-11.3 进程状态
-第十一讲 进程和线程--11.3 进程状态
-11.4 三状态进程模型
-11.5 挂起进程模型
-第十一讲 进程和线程--11.5 挂起进程模型
-11.6 线程的概念
-第十一讲 进程和线程--11.6 线程的概念
-11.7 用户线程
-第十一讲 进程和线程--11.7 用户线程
-11.8 内核线程
-第十一讲 进程和线程--11.8 内核线程
-12.1 进程切换
-第十二讲 进程控制--12.1 进程切换
-12.2 进程创建
-第十二讲 进程控制--12.2 进程创建
-12.3 进程加载
-第十二讲 进程控制--12.3 进程加载
-12.4 进程等待与退出
-第十二讲 进程控制--12.4 进程等待与退出
-13.1 总体介绍
-13.2 关键数据结构
-13.3 执行流程
-13.4 实际操作
-14.1 总体介绍
-14.2 进程的内存布局
-14.3 执行ELF格式的二进制代码-do_execve的实现
--14.3 执行ELF格式的二进制代码-do_execve的实现
-14.4 执行ELF格式的二进制代码-load_icode的实现
--14.4 执行ELF格式的二进制代码-load_icode的实现
-14.5 进程复制
-14.6 内存管理的copy-on-write机制
-15.1 处理机调度概念
-第十五讲 处理机调度--15.1 处理机调度概念
-15.2 调度准则
-15.3 先来先服务、短进程优先和最高响应比优先调度算法
--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-第十五讲 处理机调度--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
--15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
-第十五讲 处理机调度--15.4 时间片轮转、多级反馈队列、公平共享调度算法和uc
-15.5 实时调度和多处理器调度
-第十五讲 处理机调度--15.5 实时调度和多处理器调度
-15.6 优先级反置
-第十五讲 处理机调度--15.6 优先级反置
-16.1 总体介绍和调度过程
-16.2 调度算法支撑框架
-16.3 时间片轮转调度算法
-16.4 Stride调度算法
-17.1 背景
--17.1 背景
-17.2 现实生活中的同步问题
-第十七讲 同步互斥--17.2 现实生活中的同步问题
-17.3 临界区和禁用硬件中断同步方法
-第十七讲 同步互斥--17.3 临界区和禁用硬件中断同步方法
-17.4 基于软件的同步方法
-第十七讲 同步互斥--17.4 基于软件的同步方法
-17.5 高级抽象的同步方法
-第十七讲 同步互斥--17.5 高级抽象的同步方法
-18.1 信号量
--18.1 信号量
-第十八讲 信号量与管程--18.1 信号量
-18.2 信号量使用
-第十八讲 信号量与管程--18.2 信号量使用
-18.3 管程
--18.3 管程
-第十八讲 信号量与管程--18.3 管程
-18.4 哲学家就餐问题
-18.5 读者-写者问题
-19.1 总体介绍
-19.2 底层支撑
-第十九讲 实验七 同步互斥--19.2 底层支撑
-19.3 信号量设计实现
-第十九讲 实验七 同步互斥--19.3 信号量设计实现
-19.4 管程和条件变量设计实现
-第十九讲 实验七 同步互斥--19.4 管程和条件变量设计实现
-19.5 哲学家就餐问题
-20.1 死锁概念
-第二十讲 死锁和进程通信--20.1 死锁概念
-20.2 死锁处理方法
-第二十讲 死锁和进程通信--20.2 死锁处理方法
-20.3 银行家算法
-第二十讲 死锁和进程通信--20.3 银行家算法
-20.4 死锁检测
-第二十讲 死锁和进程通信--20.4 死锁检测
-20.5 进程通信概念
-第二十讲 死锁和进程通信--20.5 进程通信概念
-20.6 信号和管道
-第二十讲 死锁和进程通信--20.6 信号和管道
-20.7 消息队列和共享内存
-第二十讲 死锁和进程通信--20.7 消息队列和共享内存
-21.1 文件系统和文件
-第二十一讲 文件系统--21.1 文件系统和文件
-21.2 文件描述符
-第二十一讲 文件系统--21.2 文件描述符
-21.3 目录、文件别名和文件系统种类
-第二十一讲 文件系统--21.3 目录、文件别名和文件系统种类
-21.4 虚拟文件系统
-第二十一讲 文件系统--21.4 虚拟文件系统
-21.5 文件缓存和打开文件
-第二十一讲 文件系统--21.5 文件缓存和打开文件
-21.6 文件分配
-第二十一讲 文件系统--21.6 文件分配
-21.7 空闲空间管理和冗余磁盘阵列RAID
-第二十一讲 文件系统--21.7 空闲空间管理和冗余磁盘阵列RAID
-22.1 总体介绍
-第二十二讲 实验八 文件系统--22.1 总体介绍
-22.2 ucore 文件系统架构
-第二十二讲 实验八 文件系统--22.2 ucore 文件系统架构
-22.3 Simple File System分析
-第二十二讲 实验八 文件系统--22.3 Simple File System分析
-22.4 Virtual File System分析
-第二十二讲 实验八 文件系统--22.4 Virtual File System分
-22.5 I/O设备接口分析
-第二十二讲 实验八 文件系统--22.5 I/O设备接口分析
-22.6 执行流程分析
-23.1 I/O特点
--视频
-第二十三讲 I/O子系统--23.1 I/O特点
-23.2 I/O结构
--816C80A0F5E3B8809C33DC5901307461
-第二十三讲 I/O子系统--23.2 I/O结构
-23.3 I/O数据传输
--C58221E14388B9DB9C33DC5901307461
-第二十三讲 I/O子系统--23.3 I/O数据传输
-23.4 磁盘调度
--567A3F1FCBFB3F4C9C33DC5901307461
-第二十三讲 I/O子系统--23.4 磁盘调度
-23.5 磁盘缓存
--C327536B80D25CE79C33DC5901307461
-第二十三讲 I/O子系统--23.5 磁盘缓存
-html
--html