|
| 1 | +--- |
| 2 | +title: hkp_blog |
| 3 | +date: 2024-11-10 20:38:39 |
| 4 | +tags: |
| 5 | + - author:贺琨鹏 |
| 6 | + - repo:https://github.com/LearningOS/2024a-rcore-nakedhkp |
| 7 | +--- |
| 8 | + |
| 9 | +# 第一阶段的总结 |
| 10 | +1. 初识 Rust:语法与基础 |
| 11 | +Rust 的语法相比其他系统编程语言更为严谨,并且采用了一些新颖的设计,比如所有权(Ownership)和借用(Borrowing)模型。通过学习变量、函数、控制流、数据结构等基础内容,我逐步熟悉了 Rust 的编程风格。同时,Rust 强制规定的编译检查(如变量不可变性、类型检查)帮助我在早期阶段就养成了良好的编程习惯。 |
| 12 | + |
| 13 | +2. 内存管理与所有权 |
| 14 | +Rust 的核心设计之一是其所有权系统,这也是区别于其他语言的最显著特性之一。在 Rust 中,每个变量都有一个所有权(Owner),变量的作用域结束时会自动释放资源,无需手动管理内存,这有效地避免了悬空指针和内存泄漏问题。在学习过程中,我对以下几个概念有了深刻理解: |
| 15 | + |
| 16 | +所有权(Ownership):每个数据在同一时间只能有一个所有者。 |
| 17 | +借用(Borrowing):通过引用传递数据,允许在不改变所有权的情况下访问数据。 |
| 18 | +生命周期(Lifetimes):通过生命周期标注来管理数据的引用,使得引用的使用更加安全。 |
| 19 | +所有权系统让 Rust 在没有垃圾回收的情况下也能有效管理内存,学习这些概念后,我对资源管理的意识有了显著提升。 |
| 20 | + |
| 21 | +3. 错误处理 |
| 22 | +Rust 的错误处理也与众不同。相比传统语言使用的异常机制,Rust 使用 Result 和 Option 枚举来处理错误和可选值。这种显式的错误处理方式让我更加清楚地理解了每个操作的潜在风险,并培养了防御性编程的习惯。此外,通过使用 ? 操作符,代码变得简洁易读,让错误处理不再显得冗长。 |
| 23 | + |
| 24 | +4. 并发编程 |
| 25 | +Rust 在并发编程上的独特设计使其特别适合编写高性能的并发应用。Rust 的所有权模型通过在编译期检查数据竞争,有效防止了多线程中的常见问题,比如数据竞争、死锁等。Rust 提供的 std::thread、async/await 异步编程模型等工具使并发编程更加安全且易于管理。在学习中,我掌握了创建线程、共享数据的方式,并学会使用 Mutex 和 Arc 等工具来处理复杂的多线程情况。 |
| 26 | + |
| 27 | +5. Cargo 和生态系统 |
| 28 | +Rust 的包管理器和构建工具 Cargo 是 Rust 生态系统的重要组成部分。在学习中,我逐步熟悉了如何使用 Cargo 创建项目、管理依赖、构建和测试代码。Rust 拥有活跃的社区和丰富的库资源,通过使用第三方库,可以快速实现许多功能,这大大提升了我的开发效率。 |
| 29 | + |
| 30 | +6. 实践中的收获 |
| 31 | +理论学习之后,我通过一些实际项目(如简单的 Web 服务、命令行工具)将所学知识应用于实践。Rust 对类型和内存的严格检查在初期可能显得繁琐,但这些设计让我更清楚地理解代码结构,减少了运行时的错误。实践过程中,我逐渐感受到 Rust 的优势:高性能、可靠性和低级控制,使得 Rust 成为编写高效、安全应用的理想选择。 |
| 32 | +# 第二阶段总结 |
| 33 | + |
| 34 | +在第二阶段的学习中,我逐步深入理解了操作系统中各个功能模块的实现。这一阶段的主要任务是通过阅读和理解代码的层次结构,来掌握系统的整体设计。在初期,我对项目代码结构的理解较为模糊,但随着长时间的代码阅读和实践,我总结出了一些行之有效的阅读和理解方法: |
| 35 | + |
| 36 | +1. **分层次理解代码**:我发现从高层抽象入手去理解代码结构更为高效。首先理清最高层的抽象层次,理解其核心功能,再逐渐深入到底层实现的细节。在实验中,掌握和利用高层抽象往往能够帮助节省大量时间。 |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +### 实验总结 |
| 41 | + |
| 42 | +#### 实验一:基础系统调用实现 |
| 43 | + |
| 44 | +实验一的难度较低,因为此阶段还未实现页表管理,内核可以直接访问用户态的地址空间。实验中,系统调用的返回值可以直接使用内核中的数据。此外,通过高精度的 `get_time_us` 函数获取时间,能够确保后续实验中通过测试。为实现系统调用计数,可以在 `syscall` 函数调用时更新计数,而首次调用时间则需在 `run_first_task` 和 `run_next_task` 中进行设置。 |
| 45 | + |
| 46 | +#### 实验二:引入页表管理 |
| 47 | + |
| 48 | +在实验二中,由于实现了页表管理,系统调用设计需要改写。内核在处理传入参数时需找到实际的物理地址,并在该地址上读写数据。同时,本次实验引入了两个新的系统调用 `mmap` 和 `munmap`。因为两者涉及一段连续地址,因此在设计中需确保连续地址的映射状态(已映射或未映射)。最后,`mmap` 和 `munmap` 分别负责插入和删除页面。 |
| 49 | + |
| 50 | +#### 实验三:进程管理与调度算法实现 |
| 51 | + |
| 52 | +实验三的任务是实现 `spawn` 系统调用和 `stride` 调度算法。`spawn` 不能简单地视作 `fork + exec` 的组合。在实现前需理解 `spawn` 的语义,然后从 `fork + exec` 中提取相关代码,使得 TCB 数据结构达到所需的状态。`stride` 是一种进程调度算法,实现较为简单,按照教程提供的步骤逐步操作即可。 |
| 53 | + |
| 54 | +#### 实验四:兼容性与文件系统操作 |
| 55 | + |
| 56 | +实验四相较之前难度有所提升,需要保证现有代码的兼容性。一开始 `spawn` 存在兼容性问题,导致错误频发,最终通过重新实现 `spawn` 解决了兼容问题。此外,死锁处理是本实验的重点之一。由于某些函数(如 `find` 和 `create`)对文件系统上了锁,因此这些函数不可直接调用,但可以通过拼接部分代码来实现所需的功能。`unlink` 目录项的删除操作则需更新目录项,实验中借鉴了其他同学的思路,通过删除原内容并复制新内容实现目录项更新。 |
| 57 | + |
| 58 | +#### 实验五:死锁检测算法实现 |
| 59 | + |
| 60 | +实验五主要任务是实现死锁检测算法,该算法类似于银行家算法。教程中的描述较为简略,许多细节需要在实现中仔细推敲。`sem` 和 `mutex` 的实现大致相同。此外,`sys_get_time` 必须实现,否则某些实例可能会引发死锁。 |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +### 整体总结 |
| 65 | +本阶段实验的概念和难度相对基础,更多的挑战在于使用 Rust 编写操作系统。对于首次接触 Rust 的我来说,这种体验充满新奇,同时也加深了我对 Rust 的理解。Rust 强大的内存安全和所有权模型,在系统级编程中尤为适用 |
0 commit comments