第一阶段学习总结
学习心得
初学这门语言时总觉得是一门很繁琐的语言,需要和编译器,但是经过编译器和 clippy 方便的静态检查(折磨),发现这门语言的确是很严谨的,很多错误都是在编译期就能发现的,到后面就会发现这门语言有一种可以帮你减少错误的感觉。而且 rust 语言的创新性也是很吸引人的,下面是我认为 rust 语言的一些特色:
- 类型安全:默认不可变,默认私有。
- 内存安全:包括所有权系统(遇事不决用.clone()),借用概念,智能指针&RAII,生命周期等。
- 并发安全:多线程并发,异步并发。
- 零成本抽象:在编译期就能消除抽象的开销。对于泛型代码,rust 会在编译期将泛型代码展开,消除了泛型的开销。trait 又保证了代码的灵活性。
- 宏:rust 的宏是一种强大的元编程工具,可以指定匹配模式,并在编译器生成代码。
另外,rust 的迭代 API 也和其他语言不太一样,rust 的迭代器是惰性的,只有在需要的时候才会计算,这样可以避免一些不必要的计算。rust 中的迭代器处理同时满足了效率和代码的简短,是大部分 rust 代码中无处不在的。这些特性使得 rust 语言在系统编程中有着很大的优势。
在 rustling 过程中,有一些题目是编译器告诉我要这么做,然后就过了,虽然体验到了编译器的强大,但是对底层的原理还是似懂非懂。
Option和Result类型的使用感觉有点繁琐,各种.unwarp()。
最后在algo的题目被裸指针的转换弄得很头疼,也许链表Box::into_raw(node)可以用内部可变性和引用计数?
学习路径
rustlings 只是对 rust 中的一些基本特性做了一个简单的介绍,没有很深入的要求。对于很多特性还可以深挖,而且 rust 中还有很多有意思的特性。以下是我个人再看的一些资料:
A half-hour to learn Rust
rustlings + The Rust Programming Language - The Rust Programming Language
Introduction - Rust By Example
Effective Rust - Effective Rust
Table of Contents - Rust Cookbook
第二阶段学习总结
rCore 用比较现代的 RISCV ISA 和 rust 语言介绍并实践了 OS 相关的重要概念和基础功能,如线程调度、地址空间切换、文件系统、IPC和并发。
学习过程
整体思路:先看看每章的引言和题目,了解下一章将要学到什么。并且带着题目和测例中的疑问点看实现细节和代码。(面向测例编程)
前三章的知识更偏向ISA,riscv 还是比较简单直观的,没有很多复杂的指令和很绕的概念,只需要了解基本的 load/store 和算术运算即可。特权级相关的寄存器比较重要,需要重点记下。
lab2 从内核态复制一个结构体到用户态可以单独用一个函数封装一下,可以参考已经给出的 translated_byte_buffer
的实现,在实现 mmap
的时候要注意 SimpleRange
是左闭右开的区间,然后申请内存前枚举判断区间的相交就很显然了。
lab3 的 spawn 实现的一个坑点就是不能用 TaskControlBlock::new()
,猜测是 stdin
等不能初始化多次,所以最好还是仿照 new 和 fork 在 TaskControlBlock
结构体中写一个 spawn
。stride 算法听起来很吓人,但实现还是很简单的,只需要加入 stride
和 pass
,然后在调度时暴力计算就好了。
前面的代码还算直观,在 lab4 和 lab5 的代码就比较抽象了,为了方便实现参数乱传。
easy-fs 的层级太多了,代码量比较大,做实验时要重点看块管理器和 inode 部分。在 vfs 的 Inode
结构体中只存了 block_id
和 block_offset
,再加一个 inode_id
会对 stat
和 link
的实现比较方便,当然从block_id
和 block_offset
也可以直接反推出 inode_id
。在 unlink
操作时,我获取了一下 nlink
,即枚举这个 inode 有多少个硬链接,如果只有一个,就需要回收inode以及它对应的数据块。这个枚举还存在优化的空间。
ch8 的死锁检测算法需要在每次获取锁和释放锁时更新 Available 和 Need 矩阵,需要注意这两个矩阵的区别,什么时候用到不同的两个矩阵。同时新建线程和锁时要维护矩阵的大小。在 lock 和 down 操作执行前判断死锁。因为要更新矩阵中对应 tid 的一行,所以需要知道task在数组的位置。但是锁里面只能获得 task 对象,没法得到对应的下标。最后我用 get_trap_cx()
获取每个 task 的 trap_cx 比较。现在想想更科学的方法应该是往 TaskControlBlock
里面再加一个元素。
体会与总结
感觉 rCore 整体的代码量比较小,用用户程序测试操作系统的过程特别有意思,用户体验很友好,但是部分测例比较弱。
写完 lab 题目之后还是要尽快写总结,感觉过了几周已经忘了rustling干了啥了。