相关资料
第三阶段选题协商: 训练营项目六第三阶段选题协商
Embassy
- 文档 (原地址) : embassy
- Embassy 文档 (已汉化) : embassy-cn 0.1.0 文档
- 文档仓库 (已完成) : embassy-cn: Embassy 中文文档
- 代码注释 (进行中) : embassy
- 我自己的 : StaRainorigin/embassy
异步协程
- 教学视频 : 操作系统专题训练课
- 协程的实现 : 200行代码讲透Rust Futures
- Rust异步编程 (course.rs) : async/await 异步编程 - Rust语言圣经(Rust Course)
- Rust Runtime 设计与实现-科普篇 | 下一站 - Ihcblog!
最佳实践
- rCore-Tutorial-Book : rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档
- 嵌入式异步与RTOS的比较 : 嵌入式异步Rust与RTOS的最终决战!
- rCore-N 环境部署 : 使用教程 - Risc-V Extension N Implementation
学习记录
完成了 Embassy文档 的初步学习,并尝试翻译了一部分
对官网内容进行汉化
- 官网内容较旧,翻译一下新的
理解async,异步Rust,异步操作系统(进行中)
- 教学视频
- 200行代码将头Rust Futures
- 运行代码
- course.rs Rust圣经 中的 async 相关内容
- 运行代码
- Rust Runtime 理解、设计与实现(进行中)⭐
- 更全面地理解此内容 ⭐
嵌入式异步与 RTOS 的比较
Embassy 代码分析(进行中)
- 大体理解并翻译其中的注释(进行中)
- embassy-futures ⭐
- embassy-boot
- 理解Embassy代码设计(进行中)
- 大体理解并翻译其中的注释(进行中)
环境相关
- rCore-N 环境的部署
- rCore-tutorial 环境部署(进行中)⭐
- 理解rCore-N的源代码
- 理解rCore-N中与本项目相关的关键部分,如用户态中断,和其他与协程异步相关的内容。
找到一个可以实践的方向 ⭐
学习记录
用户态中断
用户态中断(User Interrupt)指的是能够在用户态注册中断处理函数,并且也能够在用户态触发指定的中断处理函数。
其他相关资料
x86 用户态中断 - Risc-V Extension N Implementation (gallium70.github.io)
用户态中断 - 知乎 (zhihu.com)
新CPU特性 - User space interrupt - 知乎 (zhihu.com)
CPU硬件、操作系统对并发的支持
单核情况下
- 时间片轮转:把CPU时间分割成很小的片段,然后轮流分配给各个运行中的进程使用。每个进程在被分配到一个时间片后,会执行一段时间的任务,然后让出CPU,接着下一个进程获得时间片并执行。这样,虽然在任何一个时刻,CPU只被一个进程使用,但由于时间片的切换速度非常快,使得人们感觉所有的进程都在同时运行。
- 中断技术:当CPU正在执行一个进程时,如果发生了中断(比如I/O请求、时钟中断等),CPU会暂停当前进程的执行,转而去处理中断请求。处理完中断后,CPU再回到被中断的进程继续执行。这种技术可以保证高优先级的任务(如I/O处理)能及时得到CPU的处理,从而提高了系统的响应速度和并发性。
多核情况下(对多任务处理)
在单核CPU中,多个线程或进程是并发执行的,即在同一时间段内交替运行,但在任一时刻只有一个线程或进程在执行。
在多核CPU中,可以实现并行执行,即在同一时刻,多个线程或进程在不同的核心上同时执行。一个线程只能挂在一个核上,并且每个核上的所有线程按照时间片轮转调度。
对于计算密集型任务,可以使用核心数个线程,就可以占满CPU资源,进而可以充分利用CPU。对于IO密集型任务(涉及到网络、磁盘IO的任务都是IO密集型任务),线程由于被IO阻塞,如果仍然用核心数个线程,CPU是跑不满的,于是可以使用更多个线程来提高CPU使用率。
既然有多个核心,那么当一个被正在运行的核挂起的线程可以在另一个核上继续运行。不过如果这种任务迁移非常频繁,实际上是对性能有害的,一般操作系统不会频繁地迁移任务。
同时每个核都有自己的缓存,需要一种机制来保证缓存的一致性。这通常通过缓存一致性协议(如MESI协议)来实现。
操作系统
个人理解,操作系统主要是如何更有效地利用CPU,以及负责调度上的问题。
多进程: 操作系统可以创建多个进程,每个进程独立运行,拥有自己的地址空间和资源。这些进程可以并发执行,即在同一时间段内交替运行。
多线程: 在一个进程内部,可以创建多个线程,这些线程共享进程的资源,但可以并发执行。这样,一个进程内的多个线程可以同时执行不同的任务。
中断机制: 操作系统使用中断机制来响应外部设备的请求,如键盘输入、鼠标点击等。当外部设备发出中断请求时,CPU会暂停当前任务,转而处理中断请求。处理完中断请求后,CPU再回到被中断的任务继续执行。
时间片轮转: 操作系统将CPU的运行时间划分为多个小的时间片,并依次分配给每个线程或进程。每个线程(或进程)在所分配的时间片内运行,当时间片用完后,系统内核会剥夺该线程(或进程)的CPU执行权,并将“执行权”交给下一个等待执行的线程或进程。
硬件上下文切换: 为了实现多道程序的分时共享,内核必须使用硬件上下文切换机制。当一个进程的时间片耗尽,内核会保存该进程的状态(即上下文),然后加载另一个进程的上下文,使得CPU可以继续执行新的进程。
其他
电路并行
在搜集整理资料的过程中发现一个问题,在物理上,电路本身就是并行的,并行是电路的天然属性。例子有FPGA
也许可以从其实现中获得更多启发,但本人未进行深入研究。
问题
轮询,硬件怎么做,为什么硬件做效率更高?
轮询:
轮询是一种CPU决策如何提供周边设备服务的方式。
在轮询过程中,由CPU定时发出询问,依序询问每一个周边设备是否需要其服务。
每个设备都有一个指示命令就绪的位,指示该设备的状态。
当此状态就绪即给予服务,服务结束后再问下一个周边,接着不断周而复始。
硬件轮询是由硬件直接进行的,它可以在硬件级别上快速检查设备状态,而无需占用CPU资源。
这种方式在处理高频请求或大量数据请求的设备时,效率更高。
硬件轮询可以减少系统的复杂性,因为它不需要复杂的中断处理和优先级管理。
有用户态中断之前,程序死循环了,怎么让它停下来。Ctrl + C是怎么做到的?
终端在接收到Ctrl + C后向前台进程发送SIGINT信号,而进程通常会在接收到这个信号后终止
相关资料:
关于硬件中断:一文讲透计算机的“中断”
编程语言对并发的支持
当今常用的编程语言几乎均原生自带一套实现并发的方案,同时三方库也会提供很多很多的并发方式。
相关资料:
内核态下和用户态下的线程
进程地址空间独立。存有页表切换开销。
线程有独立的堆栈,切换时保存和恢复全部的寄存器。
内核与用户线程不在相同的地址空间,用户线程只有用户栈,内核线程只有线程栈。
相关资料:
有栈协程与无栈协程
协程
协程是一种比线程更加轻量级的存在,一个线程可以有多个协程。当线程内的某一个协程运行时,其它协程必须挂起。由于协程切换是在线程内完成的,涉及到的资源比较少。可以简单理解为只是切换了寄存器和协程栈的内容。这样代价就非常小。
和传统的线程不同的是:线程是抢占式执行,当发生系统调用或者中断的时候,交由OS调度执行;而协程是通过yield 主动让出 CPU 所有权,切换到其他协程执行。
个人理解:
协程也有多种实现方式,如生成器,async/await等。
在有大量IO操作业务的情况下,我们采用协程替换线程,可以到达很好的效果,一是降低了系统内存,二是减少了系统切换开销,因此系统的性能也会提升。
在协程中尽量不要调用阻塞IO的方法,比如打印,读取文件,Socket接口等,除非改为异步调用的方式,并且协程只有在IO密集型的任务中才会发挥作用。
协程只有和异步IO结合起来才能发挥出最大的威力。
相关资料:
协程是什么?怎么来的?它有什么作用?_协程的作用
什么是协程?-腾讯云开发者社区
什么是协程?
有栈协程
有栈协程就是一种用户态线程
在 python, Golang 中就有这样的实现。
相关资料:
从头到尾理解有栈协程实现原理
手把手教你实现有栈协程和协程调度器
无栈协程
stackless
的 coroutine
无栈协程是一种特殊类型的协程,它不需要为每个协程分配一个独立的栈空间。这种设计可以大大减少内存使用,使得可以创建大量的协程。
无栈协程的实现主要基于状态机(state machine)的概念。无栈协程的本质就是在另一个角度去看问题,即同一协程协程的切换本质不过是指令指针寄存器的改变。无栈协程常常使用生成器来实现,生成器只负责生成数据。
无栈协程的优点是内存使用更加高效,可以创建大量的协程。但是,由于无栈协程没有自己的栈,所以它们不能直接调用其他函数。这就意味着无栈协程需要使用特殊的编程技巧,如状态机,来实现复杂的逻辑。
在 JavaScript 中的 Promise, 以及 async/await 可以实现看起来像无栈协程的行为。
无栈协程C++实现:
#include <iostream>
void coro_func() {
static int state = 0;
switch(state) {
case 0: goto LABEL0;
case 1: goto LABEL1;
case 2: goto LABEL2;
}
LABEL0:
for(;;) {
state = 1;
return;
LABEL1:
state = 2;
std::cout << "Hello, World!" << std::endl;
return;
LABEL2:
}
}
int main() {
for(int i = 0; i < 10; ++i) {
coro_func();
}
}
注意存在一个无限循环进行轮询的,后续可以考虑去掉
相关资料:
如何在C++17中实现stackless coroutine以及相关的任务调度器
c/c++ 无栈协程原理是什么, 该如何实现?
异步
异步编程是一种编程模式,它允许操作在后台运行,而不会阻塞主线程的执行。这种模式在处理I/O操作,如网络请求或读写文件时特别有用,因为这些操作可能需要花费大量时间来完成,而在此期间,我们不希望主线程被阻塞。
相关资料:
#main.rs
use std::time::Duration;
use tokio::time;
async fn my_coroutine() {
time::sleep(Duration::from_secs(1)).await;
println!("Coroutine finished");
}
#[tokio::main]
async fn main() {
my_coroutine().await;
}
#Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
操作系统与异步
如何深刻地理解 Unix/Linux 中同步 IO 和异步 IO?