当前课程知识点:操作系统(RISC-V) >  第十讲 进程和线程控制 >  10.1 进程切换 >  10.1 进程切换

返回《操作系统(RISC-V)》慕课在线视频课程列表

10.1 进程切换在线视频

10.1 进程切换

讲义PDF版本参见课程wiki页面:


http://os.cs.tsinghua.edu.cn/oscourse/OS2020spring/lecture10


下一节:10.2 进程创建

返回《操作系统(RISC-V)》慕课在线视频列表

10.1 进程切换课程教案、知识点、字幕

下面我们来介绍进程控制

在进程控制当中呢

我们会涉及这样几个问题

一个是在内核当中的进程切换

也就是说我一个进程

在运行过程当中

内核如何来实现它从一个进程

到另一个进程的切换

后面的三个呢

实际上为用户提供的系统调用服务

那是用户在执行它的应用的过程当中

它有需求要创建一个新的进程

好在这里头呢

我如何来创建一个新的进程

在这里头运行一个新的程序

那这个是进程加载

父进程创建子进程之后

它们俩之间呢

需要有一些协调的关系

你比如说子进程结束之后

父进程负责回收它所占用的资源

那这个时候

它们之间有一个通讯关系

这就是进程的等待和退出

下面我们一个一个的来

首先是进程切换

进程切换呢

有时候也称之为叫上下文切换

它是暂停当前运行进程

把这个进程呢

从运行状态变成其它状态

这里所谓的其它状态呢

可能会是由于进行IO操作

或者等待事件而进入等待状态

也可能是由于被抢先

又或者说时间片运行完

那转回到就绪状态

另一个是说

我把当前的进程停下来之后

那我会调度另一个进程

让它从就绪状态变成运行状态

也就是说我从就绪队列里

找一个新的进程然后恢复

并且让它继续运行

这是进程切换所要做的事情

好那具体说起来

有一些切换的时候

我们有一些什么要求呢

那在切换之前

需要去保存进程的上下文

也就是说

你下一个进程在执行过程当中

需要用到这些CPU的寄存器

状态寄存器

好那这些呢你需要先做保存

好切换到下一个进程运行的时候

在切换过来之后

下一个进程开始执行之前

我还要继续把它上一次

暂停时候的当时的

寄存器的状态恢复回来

好恢复回来之后

那它才能够从

上一次暂停的位置继续往下执行

还有一个要求是说

由于我们现在计算机系统里

进程的切换是非常频繁的

通常情况下是10毫秒左右

就会有一次进程切换

那这样以来的话

为了保证系统运行的效率

这个切换的速度必须非常快

所以通常情况下

它都是由汇编来实现的

那具体说起来我们在这里

要保存一些什么样的信息呢

实际上保存就是进程在整个

生命周期当中它所维护的信息

大致说起来呢

包括这样几个方面

寄存器

那我们在CPU里头通用寄存器

好CPU里头状态信息

然后就内存地址空间里的信息

那你说通常情况下我们

在切换的时候

内存里头的这些信息

是不会被另外一个进程

因为它各占一段区域

是不会被另一个进程所替代的

所以在这里头呢

那内存里的地址

空间内容大部分不用保存

下面我们通过一个图式

来说明进程的切换过程

那在这里头呢

我们假定系统当中有

P0和P1两个进程

它们的执行过程当中呢

先是P0处于用户态执行

那执行过程当中

P1处于空闲状态

那可能会是就绪

也可能会是等待

好那在这里头呢

执行的过程当中

碰着一个系统调用

或者是中断

假定我们这是时钟中断

那它的时间片用完了

到这儿来之后切换到内核

那切换过程当中

它需要保护现场到PCB0

也就进程零的进程控制块里头

把它的当时执行到状态

都保存下来

保存下来之后那这时候说

如果说时钟中断

时间片用完

那这时候我们需要选择

下一个就绪进程

假定这时候

你选择下一个进程是P1

好那到P1需要恢复P1现场

恢复完之后

那这时候呢

状态就已经切到进程P1了

好那这时候P1开始运行

继续运行

好运行到一段时间之后呢

假定说它的时间片又用完了

这时候又产生时钟中断

时钟中断又切回到内核状态

好那这时候它要保存

进程P1的现场

到它对应的进程控制块PCB1

好那在这里头我们假定你又决策

我需要选下一个进程

这时候又选P0

那这时候恢复P0的现场

那这时候从PCB0里头

这两个是对应的

PCB0里头恢复现场

好恢复进程状态之后

它切到进程0

然后继续执行

到这个地方呢

我们一个从进程零切换过去

再切换回来一个完整的过程

就在这儿展现出来了

跟它相关的呢

执行正常执行

然后这个地方呢

是保存现场到PCB0

从PCB0里恢复现场

好中间是PCB1

这边恢复执行到保存

那从这一过程来讲

它是比较清楚了

那这时候我们要在PCB里

记住一些什么信息了

记录进程的运行状态

好那状态呢是放这里头

然后我们把状态呢

它相同的状态

我放到一个队列里头

这时候维护出若干个队列

比如说就绪队列

它有一个起头

然后相应的进程串在一起

那可以用各种各样的办法

来形成这样一个队列

好如果是等待呢

我们就会把它分成

若干种不同类型的等待

比如说在这里头每个设备

等待的设备不同

那它有各自一个队列

比如这里列出来的

磁带01和磁盘0

好然后还有一类呢

就是处于这个

运行到退出的状态的

这时候它的收尾状态

这时候僵尸队列那它对应的

在这里头那处于这样一种状态

这是进程块里头

保存信息和它们如何来组织

好那实际上接下来

我们是说到底会有

一些什么样信息保存到

进程控制块里头呢

那不同的系统里

进程控制块呢是不一样的

比如说在我们 ucore和ucore plus里头

有一个数据结构叫PROC STRUCT

好在这个数据结构里头呢

它保存了进程的相关信息

大致的信息

我们可以把它分成这样几类

一类是进程的标识信息

比如说它的执行

是哪一个可执行文件

它的ID是多少

它的进程ID

好然后它的父进程是谁

好这是一类

然后再一类是进程的状态信息

比如说我们在这里头CPU里头

状态寄存器的相关信息

然后地址空间的起头的位置

第一级页表的起始地址在哪

然后进程的状态和它

是否允许调度等这样一些

执行状态的信息

还有一类呢是进程所占用的资源

比如说它占用的存储资源

那所有分配给

它存储那组织成

相关的数据结构MM

好那上边那个是

它占用的内核堆栈

还有一类呢

是我们保护现场用的

那在中断和进程切换的时候

它都需要保护现场

那这些现场的内容呢

我们刚才说是保存到

进程控制块里头

实际上就是指这个地方

好你两个进程需要复用的部分

就需要在这儿做保存

除此之外呢

这些进程它在

不同的时候处于不同状态

这些状态组成不同队列

那在这里还有几个

相关的指针结构

用于描述我当前进程

到底是在哪一个队列当中

好有了这些信息之后

那我们这个操作系统

就对进程的执行状态呢

有了一个准确的把握了

好我们在ucore里用到

还是比较简单的

对于实际的像Linux windows

那么这时候它的数据结构

比我们要多得多

这是进程控制块的数据结构

在ucore里的完整定义

在我们这里头呢

大家需要注意到的是

我们刚开始说的

这是进程的状态

进程的ID信息

进程ID 线程ID 组ID

然后是进程执行的相关信息

是否需要调度它的父进程是谁

然后这个地方是

进程的内存管理的数据结构

然后下边两个呢

是进程的现场保护的

上下文现场和中断保护现场

然后底下是CR3

CR3呢实际上是页表的起始地址

然后它的标志位

可执行文件的进程的名字

然后是进程的哈希表和链表

那这和我们前面讲的

这里的数据结构呢

是能够完全对得上的

我们在这儿呢是介绍的大致情况

在这里头呢实际上是完整的列表

希望同学下去之后有机会

把这个完整的列表呢

能够有一个基本的了解

好那在这里

我们需要特别说明呢

是内存地址空间的数据结构mm_struct

那在这个数据结构当中呢

我们关心的内容是说

第一个它到底有哪些内存块

内存逻辑地址空间里头

映射是在哪个地方

对应的地址空间是啥样的

好这是第一个

在这里呢

是它的第一级页表的起始地址

pde_t *pgdir

那这是地址空间的起头

然后说如果它有共享的话

那么它又共享了几次

然后如果说在这里头

有跟外存之间的置换

那这时候置换相关数据结构

好有了这些之后

那我们对进程的运行情况就了解了

这是内存管理的内存的数据结构

对应 到代码当中呢

是这个数据结构mm_struct

在这里头我们关注的几个内容呢

是它也会组织成映射的链表

然后这是页表的起始地址的指针

然后这是引用次数

和对mm数据结构进行写的时候

它相应的锁标志信号量

好然后再一个进程里头

ucore里头的进程队列

它怎么来组织呢

那在这里头呢

我们看到基本上是链表

你比如说在这里头

我们有双向 链表

然后说如果说

你这个链表很长

那这时候检索的开销是非常大的

所以在ucore里头又加了hash list

如果说这里链表长的话

先加一级hash队列

然后每一级队列里头呢

hash值相同的

再组成相应的自己的队列

那有了这些办法之后

我们就知道它在这里头

到底它的队列是如何来组织的

好那么具体的在ucore里头

它的一个切换过程是什么样子呢

不管由于什么原因

最后只要你导致切换

都会到schedule内核函数里头来

好到这个函数里头

它干些啥呢

它首先清楚调度标志

那我现在正在调度

不能再进行改调度 标志

然后我这儿呢

查找新的就绪进程

一种可能情况

就是查找完了之后我有可能

还是找回来还是我自己

那这种情况是存在的

好找着一个新的进程

然后说我修改进程的状态标志

那把前头那一个改成

是就绪或者是等待

然后把新那一个

改成是运行状态

好然后接下来进行切换

切换这儿有一个switch_to

这是最后切换的代码

好那在这里头

这个过程大致的流程就有了

好那么实际说起来我们看看这里头

这个图里说的呢

是ucore里头的函数调用关系

那不管是你由于

各种各样的情况出来之后呢

它最后都会到schedule这地方来

比如说在我们这里

是由于退出所过来的情况

好到这个schedule里头来了之后呢

它到这个地方去做选择

和这地方是在做切换

那到这个地方

最后到switch_to这一段汇编呢

它是完成切换的

而准确的切换代码

是什么样的呢

准确的切换代码是跟你平台相关的

每一个CPU平台上

它所需要保存的寄存器是不一样的

而为了保存的速度比较快

恢复速度比较快

那在这里头呢

我们所有切换代码switch_to()

都是用汇编来写成的

那大致的格局呢

是前半段保存切换过去之后

实际上改CR3

改完之后下半段恢复

然后就继续执行了

好这是进程切换的函数调用关系图

那对应到我们实际系统当中呢

这是我们的切换函数它的实现

那我们需要关注的问题

是在于这个地方在切换的时候

它会去改进程的状态

然后选择下一个被调度的进程

从调度队列当中把这个进程取出来

然后后面进行一系列的判断

那我们在这儿呢

这一部分内容呢

我们直接看关注的是它的调用图

那在这儿我们可以看到

schedule()这个函数它调用的地方呢

基本上是我们各种事件出现的时候

你比如说数据发送

然后这个后面会讲到信号量的触发

然后接收到事件

CPU处于空闲状态

发送消息等等一些信息

最后都会导致到我这schedule()

schedule()里呢我们刚才说到proc_run()

这是我们这里关键的函数

到这个地方下来之后有一个

switch_to()

在这个函数里头呢

实际上我们通过跳转

转到我们的汇编代码上了

这个汇编代码呢

就是我们这里的这一段

在这里头呢前面是保存

上一个进程的寄存器的工作

下边是从堆栈当中恢复

进入运行状态的进程的寄存器的值

恢复完毕之后然后返回

那就新的进程就开始继续运行了

那在刚才那个地方呢

switch实际上是通过这里头

这一句C语言的函数

最后跳转到刚才的

这个汇编代码当中来

操作系统(RISC-V)课程列表:

第一讲 操作系统概述

-1.1 课程概述

--课程概述

-1.2 教学安排

--视频

-1.3 什么是操作系统

--Video

-1.4 为什么学习操作系统,如何学习操作系统

--Video

-1.5 操作系统实例

--视频

-1.6 操作系统的演变

--视频

-1.7 操作系统结构

--视频

-1.8 OS实验概述

--视频

第二讲 操作系统与系统结构和程序设计语言

-2.1 从OS角度看计算机系统

--2.1 从OS角度看计算机系统

-2.2 从OS角度看RISC-V

--2.2 从OS角度看RISC-V

-2.3 Rust语言与系统编程

--2.3 Rust语言与系统编程

-2.4 RISC-V CPU启动

--2.4 RISC-V CPU启动

-2.5 RISC-V CPU启动进一步分析

--2.5 RISC-V CPU启动进一步分析

第三讲 中断、异常和系统调用

-3.1 基本概念与原理

--3.1 基本概念与原理

-3.2 硬件架构支持

--3.2 硬件架构支持

-3.3 中断处理机制

--3.3.1 中断处理机制–Overview

--3.3.2 中断处理机制–Detail-1

--3.3.3 中断处理机制–Detail-2

--3.3.4 中断处理机制–Detail-3

--3.3.5 中断处理机制–Summary

-3.4 系统调用

--3.4 系统调用

第四讲 物理内存管理: 连续内存分配

-4.1 计算机体系结构和内存层次

--4.1 计算机体系结构和内存层次

-4.2 地址空间和地址生成

--4.2 地址空间和地址生成

-4.3 连续内存分配

--4.3 连续内存分配

-4.4 碎片整理

--4.4 碎片整理

-4.5 伙伴系统

--4.5 伙伴系统

-4.6 SLAB分配器

--4.6 SLAB分配器

第五讲 物理内存管理: 非连续内存分配

-5.1 非连续内存分配的需求背景

--5.1 非连续内存分配的需求背景

-5.2 段式存储管理

-- 5.2 段式存储管理

-5.3 页式存储管理

--5.3 页式存储管理

-5.4 页表概述

--5.4 页表概述

-5.5 快表和多级页表

--5.5 快表和多级页表

-5.6 RISC-V页映射机制

--5.6 RISC-V页映射机制

-5.7 使能RISC-V页表

--5.7 使能RISC-V页表

第六讲 虚拟存储概念

-6.1 虚拟存储的需求背景

--6.1 虚拟存储的需求背景

-6.2 覆盖和交换

--6.2 覆盖和交换

-6.3 局部性原理

--6.3 局部性原理

-6.4 虚拟存储概念

--6.4 虚拟存储概念

-6.5 虚拟页式存储

--6.5 虚拟页式存储

-6.6 缺页异常

--6.6 缺页异常

-6.7 RISC-V缺页异常

--6.7 RISC-V缺页异常

第七讲 虚拟存储:局部页面置换算法

-7.1 页面置换算法的概念

--7.1 页面置换算法的概念

-7.2 最优算法、先进先出算法和最近最久未使用算法

--7.2 最优算法、先进先出算法和最近最久未使用算法

-7.3 时钟置换算法和最不常用算法

--7.3 时钟置换算法和最不常用算法

-7.4 Belady现象和局部置换算法比较

--7.4 Belady现象和局部置换算法比较

-7.5 页表自映射

--7.5 页表自映射

第八讲 虚拟存储:全局页面置换算法

-8.1 工作集置换算法

--8.1 工作集置换算法

-8.2 缺页率置换算法

--8.2 缺页率置换算法

-8.3 抖动和负载控制

--8.3 抖动和负载控制

-8.4 面向缓存的页替换算法

--8.4.1 面向缓存的页替换算法-FBR

--8.4.2 面向缓存的页替换算法-LRU-K 2Q

--8.4.3 面向缓存的页替换算法-LIRS

第九讲 进程和线程

-9.1 进程的概念

--11.1 进程的概念

-9.2 进程控制块

--9.2 进程控制块

-9.3 进程状态

--9.3 进程状态

-9.4 三状态进程模型

--9.4 三状态进程模型

-9.5 挂起进程模型

--9.5 挂起进程模型

-9.6 线程的概念

--9.6 线程的概念

-9.7 用户线程

--9.7 用户线程

-9.8 内核线程

--9.8 内核线程

-9.9 进程地址空间与熔断 (meltdown) 漏洞

--9.9 进程地址空间与熔断 (meltdown) 漏洞

第十讲 进程和线程控制

-10.1 进程切换

--10.1 进程切换

-10.2 进程创建

--10.2 进程创建

-10.3 进程加载

--10.3 进程加载

-10.4 进程等待与退出

--10.4 进程等待与退出

-10.5 rCore进程和线程控制

--10.5 rCore进程和线程控制

第十一讲 处理机调度

-11.1 处理机调度概念

--11.1 处理机调度概念

-11.2 调度准则

--11.2 调度准则

-11.3 先来先服务、短进程优先和最高响应比优先调度算法

--11.3 先来先服务、短进程优先和最高响应比优先调度算法

-11.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架

--11.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架

-11.5 实时调度

--11.5 实时调度

-11.6 优先级反置

--11.6 优先级反置

-11.7 rCore调度框架

--11.7 rCore调度框架

第十二讲 多处理机调度

-12.1 对称多处理与多核架构

--12.1 对称多处理与多核架构

-12.2 多处理器调度概述

--12.2 多处理器调度概述

-12.3 O(1)调度

--12.3 O(1)调度

-12.4 CFS调度

--12.4 CFS调度

-12.5 BFS调度算法

--12.5 BFS调度算法

第十三讲 同步互斥

-13.1 背景

--13.1 背景

-13.2 现实生活中的同步问题

--13.2 现实生活中的同步问题

-13.3 临界区和禁用硬件中断同步方法

--13.3 临界区和禁用硬件中断同步方法

-13.4 基于软件的同步方法

--13.4 基于软件的同步方法

-13.5 高级抽象的同步方法

--13.5 高级抽象的同步方法

第十四讲 信号量与管程

-14.1 信号量

--14.1 信号量

-14.2 信号量使用

--14.2 信号量使用

-14.3 管程

--14.3 管程

-14.4 哲学家就餐问题

--14.4 哲学家就餐问题

-14.5 读者-写者问题

--14.5 读者-写者问题

-14.6 Rust语言中的同步机制

--14.6 Rust语言中的同步机制

第十五讲 死锁和并发错误检测

-15.1 死锁概念

--15.1 死锁概念

-15.2 死锁处理方法

--15.2 死锁处理方法

-15.3 银行家算法

--15.3 银行家算法

-15.4 死锁检测

--15.4 死锁检测

-15.5 并发错误检测

--15.5 并发错误检测

第十六讲 进程通信

-16.1 进程通信概念

--16.1 进程通信概念

-16.2 信号和管道

--16.2 信号和管道

-16.3 Linux信号机制

--16.3 Linux信号机制

-16.4 消息队列和共享内存

--16.4 消息队列和共享内存

-16.5 D-Bus机制

--16.5 D-Bus机制

-16.6 Binder机制

--16.6 Binder机制

第十七讲 文件系统概念

-17.1 文件系统和文件

--17.1 文件系统和文件

-17.2 文件描述符

--17.2 文件描述符

-17.3 目录、文件别名和文件系统种类

--17.3 目录、文件别名和文件系统种类

-17.4 虚拟文件系统

--17.4 虚拟文件系统

-17.5 文件缓存和打开文件

--17.5 文件缓存和打开文件

-17.6 文件分配

--17.6 文件分配

-17.7 空闲空间管理和冗余磁盘阵列RAID

--17.7 空闲空间管理和冗余磁盘阵列RAID

第十八讲 文件系统实例

-18.1 FAT文件系统

--18.1 FAT文件系统

-18.2.1 EXT4文件系统-历史

--18.2.1 EXT4文件系统-历史

-18.2.2 EXT4文件系统-支持大容量存储

--18.2.2 EXT4文件系统-支持大容量存储

-18.2.3 EXT4文件系统-支持恢复异常

--18.2.3 EXT4文件系统-支持恢复异常

-18.3 ZFS文件系统

--18.3 ZFS文件系统

第十九讲 I/O子系统

-19.1 I/O特点

--19.1 I/O特点

-19.2 I/O结构

--19.2 I/O结构

-19.3 I/O数据传输

--19.3 I/O数据传输

-19.4 磁盘调度

--19.4 磁盘调度

-19.5 Linux I/O子系统

--19.5 Linux I/O子系统

第二十讲 内核与程序设计语言

-20.1 Linux内核错误分析

--20.1 Linux内核错误分析

-20.2.1 用rust写操作系统-系统编程语言rust

--20.2.1 用rust写操作系统-系统编程语言rust

-20.2.2 用rust写操作系统-rust与操作系统开发

--20.2.2 用rust写操作系统-rust与操作系统开发

第二十一讲 异步编程 (Asynchronous Programming)

-21.1 Background

--21.1 Background

-21.2 Futures in Rust

--21.2 Futures in Rust

-21.3 Generators and async/await

--21.3 Generators and async/await

-21.4 Self-Referential Structs & Pin

--21.4 Self-Referential Structs & Pin

-21.5 Waker and Reactor

--21.5 Waker and Reactor

第二十二讲 Virtual Machine Monitor

-22.1 Overview

--22.1 Overview

-22.2.1 How VMM works - CPU

--22.2.1 How VMM works - CPU

-22.2.2 How VMM works - memory & I/O

--22.2.2 How VMM works - memory & I/O

10.1 进程切换笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。