[rCore学习笔记 021]多道程序与分时任务

写在前面

本随笔是非常菜的菜鸡写的。如有问题请及时提出。

可以联系:1160712160@qq.com

GitHhub:https://github.com/WindDevil (目前啥也没有

导读

这里就是第三章的开头了,由于我的巨菜,导致天天半天理解不了关键点所在,唉,实在是太折磨人.

遵照上一章开头的时候的优良传统,我个人感觉每次手册给出feature都要想一想上一章对于这个功能我们是怎么实现的,现在的功能是有什么好处.这样可以加深印象.

提高系统的性能和效率是操作系统的核心目标之一,本章展现了操作系统在性能上的一系列功能改进:

  • 通过提前加载应用程序到内存,减少应用程序切换开销
  • 通过协作机制支持程序主动放弃处理器,提高系统执行效率
  • 通过抢占机制支持程序被动放弃处理器,保证不同程序对处理器资源使用的公平性,也进一步提高了应用对 I/O 事件的响应效率

同样地,一定要去阅读官方文档,可能我关注的点并不够全面.

这里进行自己的头脑风暴,思考实现方式:

  1. 提前加载应用程序到内存的方法:
    1. 使用更多的内存,把所有的应用程序一股脑地加载进去,然后把在内存中的地址返回
    2. 如果我不是把所有的应用程序全部都加载在内存中,那么我们是怎么知道等一下要运行哪个应用程序的呢?
  2. 实现协作机制和抢占机制的方法,感觉它写的是应用程序主动放弃处理器,但是实际上做实现的时候我又想利用类似于中断的方式解决问题,就是保存上下文然后跳转那一套东西,至于如何计算时间,就很难想到其内部实现,我感觉这时候一定要使用到定时器了.

总而言之,脑子里还是之前使用RT-Thread和FreeRTOS的时候的幼稚的.APP1->delay->抢占->APP2->APP1这种想法.

这时候就需要更深入的了解.

可以在这里了解到,在 协作式 模式下,需要程序员主动在程序中写一个 主动放弃处理器 的调用请求.

而对于 抢占式 , 则是使用 中断 直接打断程序运行,从而保证一个应用程序在执行完 一段时间 以后一定会让出处理器,这里截取一段官方文档的描述:
操作系统可进一步利用某种以固定时长为时间间隔的外设中断(比如时钟中断)来强制打断一个程序的执行,这样一个程序只能运行一段时间(可以简称为一个时间片, Time Slice)就一定会让出处理器,且操作系统可以在处理外设的 I/O 响应后,让不同应用程序分时占用处理器执行,并可通过统计程序占用处理器的总执行时间,来评估运行的程序对处理器资源的消耗。我们把这种运行方式称为 分时共享(Time Sharing) 或 抢占式多任务(Multitasking) ,也可合并在一起称为 分时多任务 。

这里就从脑海的深处想起来关于 裸机编程 的东西,就是使用 定时器 中断来实现分时复用,那么和使用 抢占式 的分时复用有什么区别呢?

  1. 定时器的数量有限
  2. 使用软定时器解决问题对于固定行为固定时长的程序有效,但是对于含有各种复杂分支的程序就比较难办

这里还有一个问题,就是对于 波形采样 这样 时间敏感 型的任务,可以放心把它交给OS吗?还是说需要结合 定时器中断OS 调度.那么怎么结合呢?

最后截取官方文档对这章实现的定位和分类:
本章所介绍的多道程序和分时多任务系统都有一些共同的特点:在内存中同一时间可以驻留多个应用,而且所有的应用都是在系统启动的时候分别加载到内存的不同区域中。由于目前计算机系统中只有一个处理器核,所以同一时间最多只有一个应用在执行(即处于运行状态),剩下的应用处于就绪状态或等待状态,需要内核将处理器分配给它们才能开始执行。一旦应用开始执行,它就处于运行状态了。
本章主要是设计和实现建立支持 多道程序 的二叠纪“锯齿螈” 1 初级操作系统、支持 多道程序 的三叠纪“始初龙” 2 协作式操作系统和支持 分时多任务 的三叠纪“腔骨龙” 3 抢占式操作系统,从而对可支持运行一批应用程序的多种执行环境有一个全面和深入的理解,并可归纳抽象出 任务 、 任务切换 等操作系统的概念。

实践体验

同样地,我们可以很方便地利用rCore-Tutorial-v3,体验这两种操作系统的实现.

首先我们需要切换到文件夹下cd ~/App/rCore-Tutorial-v3.

体验多道程序操作系统

切换到多道操作系统并且运行:

git checkout ch3-coop
cd os
make run

这里注意,如果你修改了分支的内容导致不能切换分支,你可以使用git checkout -- .来丢弃所有的更改,这样就可以切换到新的分支.

运行结果:

[rustsbi] RustSBI version 0.3.1, adapting to RISC-V SBI v1.0.0
.______       __    __      _______.___________.  _______..______   __
|   _  \     |  |  |  |    /       |           | /       ||   _  \ |  |
|  |_)  |    |  |  |  |   |   (----`---|  |----`|   (----`|  |_)  ||  |
|      /     |  |  |  |    \   \       |  |      \   \    |   _  < |  |
|  |\  \----.|  `--'  |.----)   |      |  |  .----)   |   |  |_)  ||  |
| _| `._____| \______/ |_______/       |__|  |_______/    |______/ |__|
[rustsbi] Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
[rustsbi] Platform Name      : riscv-virtio,qemu
[rustsbi] Platform SMP       : 1
[rustsbi] Platform Memory    : 0x80000000..0x88000000
[rustsbi] Boot HART          : 0
[rustsbi] Device Tree Region : 0x87000000..0x87000f02
[rustsbi] Firmware Address   : 0x80000000
[rustsbi] Supervisor Address : 0x80200000
[rustsbi] pmp01: 0x00000000..0x80000000 (-wr)
[rustsbi] pmp02: 0x80000000..0x80200000 (---)
[rustsbi] pmp03: 0x80200000..0x88000000 (xwr)
[rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
[kernel] Hello, world!
AAAAAAAAAA [1/5]
BBBBBBBBBB [1/2]
CCCCCCCCCC [1/3]
AAAAAAAAAA [2/5]
BBBBBBBBBB [2/2]
CCCCCCCCCC [2/3]
AAAAAAAAAA [3/5]
Test write_b OK!
[kernel] Application exited with code 0
CCCCCCCCCC [3/3]
AAAAAAAAAA [4/5]
Test write_c OK!
[kernel] Application exited with code 0
AAAAAAAAAA [5/5]
Test write_a OK!
[kernel] Application exited with code 0
All applications completed!

这个运行结果是这样的 [ 1/5 ]的意思是执行到了第五次执行中的第一次,这样就很容易理解这个程序的结果了,也就是轮流在执行都已经被加载到内存中的分别能输出一串A,B,C的三个程序.

然后执行到限制的次数为止.

体验分时多任务操作系统

cd ~/App/rCore-Tutorial-v3,再次回到根文件下,切换到分时多任务操作系统并运行:

git checkout ch3
cd os
make run

运行结果:

[rustsbi] RustSBI version 0.3.1, adapting to RISC-V SBI v1.0.0
.______       __    __      _______.___________.  _______..______   __
|   _  \     |  |  |  |    /       |           | /       ||   _  \ |  |
|  |_)  |    |  |  |  |   |   (----`---|  |----`|   (----`|  |_)  ||  |
|      /     |  |  |  |    \   \       |  |      \   \    |   _  < |  |
|  |\  \----.|  `--'  |.----)   |      |  |  .----)   |   |  |_)  ||  |
| _| `._____| \______/ |_______/       |__|  |_______/    |______/ |__|
[rustsbi] Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
[rustsbi] Platform Name      : riscv-virtio,qemu
[rustsbi] Platform SMP       : 1
[rustsbi] Platform Memory    : 0x80000000..0x88000000
[rustsbi] Boot HART          : 0
[rustsbi] Device Tree Region : 0x87000000..0x87000f02
[rustsbi] Firmware Address   : 0x80000000
[rustsbi] Supervisor Address : 0x80200000
[rustsbi] pmp01: 0x00000000..0x80000000 (-wr)
[rustsbi] pmp02: 0x80000000..0x80200000 (---)
[rustsbi] pmp03: 0x80200000..0x88000000 (xwr)
[rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
[kernel] Hello, world!
power_3 [10000/200000]
power_3 [20000/200000]
power_3 [30000/200000]
power_3 [40000/200000]
power_3 [50000/200000]
power_3 [60000/200000]
power_3 [70000/200000]
power_3 [80000/200000]
power_3 [90000/200000]
power_3 [100000/200000]
power_3 [110000/200000]
power_3 [120000/200000]
power_3 [130000/200000]
power_3 [140000/200000]
power_3 [150000/200000]
power_3 [160000/200000]
power_3 [170000/200000]
power_3 [180000/200000]
power_3 [190000/200000]
power_3 [200000/200000]
3^200000 = 871008973(MOD 998244353)
Test power_3 OK!
[kernel] Application exited with code 0
power_5 [10000/140000]
power_5 [20000/140000]
power_5 [30000/140000]
power_5 [40000/140000]
power_5 [50000/140000]
power_5 [60000/140000]
power_5 [70000/140000]
power_5 [80000/140000]
power_5 [90000/140000]
power_5 [100000/140000]
power_5 [110000/140000]
power_5 [120000/140000]
power_7 [10000/160000]
power_7 [20000/160000]
power_7 [30000/160000]
power_7 [40000/160000]
power_7 [50000/160000]
power_7 [60000/160000]
power_7 [70000/160000]
power_7 [80000/160000]
power_7 [90000/160000]
power_7 [100000/160000]
power_7 [110000/160000]
power_7 [120000/160000]
power_7 [130000/160000]
power_7 [140000/160000]
power_7 [150000/160000]
power_7 [160000/160000]
7^160000 = 667897727(MOD 998244353)
Test power_7 OK!
[kernel] Application exited with code 0
power_5 [130000/140000]
power_5 [140000/140000]
5^140000 = 386471875(MOD 998244353)
Test power_5 OK!
[kernel] Application exited with code 0
Test sleep OK!
[kernel] Application exited with code 0
All applications completed!

官方文档对它的解析为:
分时多任务系统应用分为两种。编号为 00/01/02 的应用分别会计算质数 3/5/7 的幂次对一个大质数取模的余数,并会将结果阶段性输出。编号为 03 的应用则会等待三秒钟之后再退出。以 k210 平台为例,我们将会看到 00/01/02 三个应用分段完成它们的计算任务,而应用 03 由于等待时间过长总是最后一个结束执行。

代码结构

这是本章 多道程序操作系统 的代码结构:

这是上一章的代码结构,可以看到本章的 多道任务 是多了几个APP的框图在U-Mode:

这是更进一步的 协作式分时操作系统 的框图:

首先先说我自己看到这张图的感受,

  1. 在原本的多道系统的基础上为每个APP都增加了一个保存上下文的栈.
  2. 把AppManager拆分成Loader和TaskManager.
  3. 增加了任务状态和任务上下文的概念,应该是用于分时复用,但是不知道具体怎么实现的.
  4. 为CPU增加了一条时间线,应该是用于分时复用,但是不知道具体怎么实现的.

通过查看官方文档,我们可以另外补充到一些我们不知道的东西:
如果当前应用程序正在运行,则该应用对应的任务处于运行(Running)状态;如果该应用主动放弃处理器,则该应用对应的任务处于就绪(Ready)状态。操作系统进行任务切换时,需要把要暂停任务的上下文(即任务用到的通用寄存器)保存起来,把要继续执行的任务的上下文恢复为暂停前的内容,这样就能让不同的应用协同使用处理器了。

这是更进一步的 抢占式多任务操作系统 的框图:

同样地,先观察这个图讲出自己的感受:

  1. 初看和 协作式 没有什么不同之处
  2. 细看发现在Trap_handler,里边增加了Timer的调度,可能和我想得一样是用定时器来触发中断然后实现时间片的轮转.

实际上官方文档的描述也大致如此.

本章代码导读

这一部分的作者写得太好了,我直接无话可说.直接点击观看吧.

本章的重点是实现对应用之间的协作式和抢占式任务切换的操作系统支持。与上一章的操作系统实现相比,有如下一些不同的情况导致实现上也有差异:

  • 多个应用同时放在内存中,所以他们的起始地址是不同的,且地址范围不能重叠
  • 应用在整个执行过程中会暂停或被抢占,即会有主动或被动的任务切换

这些实现上差异主要集中在对应用程序执行过程的管理、支持应用程序暂停的系统调用和主动切换应用程序所需的时钟中断机制的管理。

对于第一个不同情况,需要对应用程序的地址空间布局进行调整,每个应用的地址空间都不相同,且不能重叠。这并不要修改应用程序本身,而是通过一个脚本 build.py 来针对每个应用程序修改链接脚本 linker.ld 中的 BASE_ADDRESS ,让编译器在编译不同应用时用到的 BASE_ADDRESS 都不同,且有足够大的地址间隔。这样就可以让每个应用所在的内存空间是不同的。

对于第二个不同情况,需要实现任务切换,这就需要在上一章的 Trap 上下文切换的基础上,再加上一个 Task 上下文切换,才能完成完整的任务切换。这里面的关键数据结构是表示应用执行上下文的 TaskContext 数据结构和具体完成上下文切换的汇编语言编写的 __switch 函数。一个应用的执行需要被操作系统管理起来,这是通过 TaskControlBlock 数据结构来表示应用执行上下文的动态执行过程和状态(运行态、就绪态等)。而为了做好应用程序第一次执行的前期初始化准备, TaskManager 数据结构的全局变量实例 TASK_MANAGER 描述了应用程序初始化所需的数据, 而对 TASK_MANAGER 的初始化赋值过程是实现这个准备的关键步骤。

应用程序可以在用户态执行中主动暂停,这需要有新的系统调用 sys_yield 的实现来支持;为了支持抢占应用执行的抢占式切换,还要添加对时钟中断的处理。有了时钟中断,就可以在确定时间间隔内打断应用的执行,并主动切换到另外一个应用,这部分主要是通过对 trap_handler 函数中进行扩展,来完成在时钟中断产生时可能进行的任务切换。 TaskManager 数据结构的成员函数 run_next_task 来具体实现基于任务控制块的任务切换,并会具体调用 __switch 函数完成硬件相关部分的任务上下文切换。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于FPGA的2FSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR

1.算法仿真效果本系统在以前写过的FSK调制解调系统的基础上,增加了高斯信道模块,误码率统计模块,可以验证不同SNR情况下的FSK误码情况。vivado2019.2仿真结果如下(完整代码运行后无水印):SNR=16dbSNR=10dbSNR=5dbSNR=0dbRTL结构图如下:2.算法涉及理论知识概要频移键控是…

Contest5400 - 网络流-1

RTContest A 签到题 B 最大流 Dinic 板子。 Dinic 的整体结构: ll dinic() {ll ans = 0;while (bfs()) { // 如果 s 还有能到 t 的增广路fill(cur+1, cur+n+1, 0); // 当前弧优化的预处理,暂时不用管ans += dfs(s, INF); // 多路增广}return ans; }BFS 建分层图: bool bfs()…

MySQL45讲基础篇

基础篇 01 | 基础架构:一条SQL查询语句是如何执行的? 你好,我是林晓斌。 这是专栏的第一篇文章,我想来跟你聊聊 MySQL的基础架构。我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于MySQL的学习也是这样。平…

Datawhale AI 暑期夏令营 第四期Task3

Transformer架构 Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构,它在2017年由Vaswani等人首次提出。Transformer架构引入了自注意力机制(self-attention mechanism),这是一个关键的创新,使其在处理序列数据时…

基于IEEE802.11g标准的OFDM信号帧检测matlab仿真

1.程序功能描述现有的无线通信信道共享的无线信号识别为将来的软件定义的无线电系统是一个巨大的挑战。在这个项目中,学生将制定IEEE802.11无线信号在AWGN信道,利用MATLAB/ Simulink技术来识别。一个完整的发射机模式将开发和实施。 在AWGN信道下的性能进行评估。基于IEEE802…

羽毛球比赛积分系统03

羽毛球比赛积分系统 1、产品愿景目标用户 学校的体育工作人员(老师、教练、裁判),学生和教师选手,赛事组织者,志愿者等羽毛球比赛的参与者。他们的需要或机会简化赛事安排和管理。 提高比赛的公正性和透明度。 实时掌握比赛成绩和排名。 增强赛事互动和参与体验。产品名称…

实现一个终端文本编辑器来学习golang语言:第二章Raw模式下的输入输出

从第二章开始,在每个小节的最后都会有一些代码实操作业,你可以选择自己完成(比较推荐),再对照我的实现方式,当然也可以直接看我的代码实现。不过,之后的各个功能实现,我都会基于我先前的代码实现版本,在它的基础上进行扩展。 首先,我们先来解决第一章遗留的第一个问题…

protobuf pwn题专项

protobuf pwn 准备工作 安装protobuf编译器 sudo apt-get install libprotobuf-dev protobuf-compiler 安装python依赖库 pip3 install grpcio pip3 install grpcio-tools googleapis-common-protos安装pbtk git clone https://github.com/marin-m/pbtkggbond 来自DubheCTF202…

JAVA游戏源码:魔塔大学生练手项目java学习项目

学习java朋友们,福利来了,今天小编给大家带来了一款魔塔源码。注意:此源码仅供学习使用!! 视频演示 源码搭建和讲解 启动main入口://************************************************************************ // ************完整源码移步: gitee典康姆/hadluo/java_g…

第五周进度报告

这周主要学习了java的一些基础知识,接下来的任务继续学习javaAPI部分的知识 鼠标监听机制 - MouseListener键盘监听机制 -KeyListener常用APIpackage me.Study;public class Test {public static void main(String[] args) {//获取到当前时间的毫秒值long start = System.curre…

dotnet hello world

参考资料 dotnet 命令参考 使用 dotnet test 和 xUnit 在 .NET 中对 C# 进行单元测试 Declaring InternalsVisibleTo in the csproj XUnit输出消息 创建控制台项目 # 创建项目目录 md DotnetStudy cd DotnetStudy# 创建解决方案 dotnet new sln # 创建控制台项目,-n: 名称,--us…