You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 用户故事|艾同学:路虽远,行则将至
你好,我是艾恩凝。很高兴受邀来写用户故事,可以“吐槽”一下与我结缘的操作系统实战专栏。不对,是夸赞。
其实,这门课在去年底宣传的时候,我就知道了。那时朋友圈铺天盖地在发消息,可以说想不知道都难,当时我只以为是单纯的广告,所以并没有仔细了解。
就这样我与这么好的一门课擦肩而过。现在回头看来只是缘分未到有缘毕竟终会相见。今年3月份的时候深入了解后我果断入手学完以后用一句话概括感受的话课程讲的都是纯纯的干货。
具体来说我的学习始于2022年3月24日完结于2022年5月24日刚刚跑出最终效果我就迫不及待要来分享了。想一想也好巧啊正好是两个月的时间比我有女朋友的时间还长
在留言区我也有过不少打卡记录,不过整个课程学完了,还是有很多想说的,正好通过用户故事与你分享。
因为每个人的基础都不同,所以课程感受到的难度也是不一样的。我会跟你聊聊我的知识储备,学习方式还有一些课程实验的实战经验。希望能够给一起学习的你带来启发。
## 知识储备
首先我交代一下自己的知识储备背景吧。目前我在东北某地某高校读研研二喜欢嵌入式方面的技术特别是对系统非常感兴趣。过去我移植过U-Boot裁剪过Linux内核也简单实现过FreeRTOS内核的进程调度。
过去的技术积累对我学习这门课也有一定的帮助。比如说在我看来Cosmos的进程调度就跟FreeRTOS内核的设计思想很类似使用几个优先级链表来实现进程调度。如果你还想看看我做过的软件项目和技术文章可以通过[这里](https://dxinxia.top)了解。
我本科是计算机科学与技术专业,基础核心课不说融会贯通,但很基础的课程像数据结构、基础算法等,我自认学得还不错。
语言方面最基础的C语言尤其是指针我也研究过如果能明白指针和内存的关系我想指针就是纸老虎了。至于汇编语言我会写一些简单的ARM汇编但对于x86汇编还是很陌生。最后是Linux基础常用指令以及GCC、Makefile、shell的使用等等我都有涉猎。
列了这么多基础知识,你是否好奇我主要通过什么来学习呢?这里我要强烈建议你选一些经典图书阅读。因为走了这么多弯路,我觉得读书的效率还是最高的。我把学这门课之前读过的书目,以及我的阅读方法和读后简评汇总成了一张表,你可以参考一下。
![图片](https://static001.geekbang.org/resource/image/93/76/939207efdd370e5d0083e1b5348c4d76.jpg?wh=1920x1083)
其实,看书不一定要从头看到尾。我更喜欢结合自己当前主攻的技术问题来学习,也就是用到哪部分知识,再相应深入研究。这样你的印象才能更深刻。毕竟漫无目的地学习,效率会比较低下。
比如我们想要了解C语言编译链接的过程就可以仔细看看CSAPP的第七章这部分对链接原理的讲解非常清晰知识结构也更加系统。比起搜索碎片化的网络解读你不如沉下心读读书这样学习效率会更高。
另外,我也做过大大小小的嵌入式项目。总体来说,个人知识储备是广而不深,怀揣着对系统的热爱,我开始学习这门操作系统实战课。
## 学习方式
不管你是出于什么目的来学习这门课。我觉得最重要的是坚持下来。坚持,是成功者必须具备的条件。有的人能为了追到一个妹子一直坚持,我觉得学新知识也应该如此(开个玩笑)。坚持下来,迎难而上,你才能有所收获。
其次,开始这门课,应该给自己定一个明确的目标。比如我的目标是:不只学习新的理论知识,还要实战,也就是跟着写代码。毕竟理论跟实战真的不一样,虽然这无形之中增加了难度,但回头来看,我也感谢自己这么选择。
这门课程的实战非常接近一个项目工程,都是在前面的基础上一点点加功能,完成之后,有种逐渐建起一座塔的那种成就感。其实就算你不能完整实战,或者现阶段,你只能先理解课程里的理论思路,我觉得学完也会有不少收获。
除了坚持和基于目标努力,我还把整个学习任务做了一定的拆解。在计算机的世界,复杂问题总能拆分成相对好解决的子问题,复杂的工程也常常可以采取“分而治之”的策略。
**那我是怎么拆分学习任务的呢?**其实课程的目录结构就很好。
我觉得应该把整体内容分成三大块:准备期,内存部分和余下的部分。当然每个人可以不一样,根据自己本身实际情况划分即可。每学习一章节,我都过了三遍。此处的学习不是浏览下来理解就完事了,那只能停留在理论上。
具体过程我是这样安排的。第一遍学习理解理论知识。第二遍做思维导图,理解程序过程,记录知识点等等。
第三遍最重要,并且我花的时间最长,那就是实战写代码。同时为了养成良好的习惯,我会强制自己写注释。毕竟有不少代码相对复杂,哪怕前面已经理解了,过几天也真的不知道这个地方干了什么。同时像有些结构体之类的代码,我甚至打印出来做分析。
后面这张图是我打印出来的一部分代码,也分享给你感受一下。
![图片](https://static001.geekbang.org/resource/image/27/07/273839617cb13410cfbea93fde639807.jpg?wh=1920x1440 "部分打印的代码")
这里我选择了Grub启动、二级引导器以及内存部分的导图给你展示一下。更多导图我就不一一展示了你可以通过[这里](https://aeneag.xyz/virginOS)获取。
![图片](https://static001.geekbang.org/resource/image/c5/14/c5f8ac6e30b6599a4b0d9d784b98df14.jpg?wh=1920x1584 "Grub启动导图节选")
![图片](https://static001.geekbang.org/resource/image/24/ca/247cd1c9ee918a0a392f2e5303441eca.jpg?wh=1920x1359 "二级引导器导图")
![图片](https://static001.geekbang.org/resource/image/c5/3f/c57cc5b2f7054b6c83baf7887182083f.jpg?wh=1920x1623 "内存部分导图节选")
我觉得这门课最大的难度就是内存部分。从我自己的体验看内存一过基本可以一马平川。Cosmos内存的设计思想与Buddy、Slab类似而进程的实现方式与RTOS类似我想你只要明白了其中的一种其他系统的也会很容易理解。而对于内存对象最重要的还是理解概念然后再专注于代码细节。
## 调试程序跟Bug斗其乐无穷
前面说过,我并不满足于单纯学习理论知识,而是立下了把代码实现出来这个目标。这两个月的时间,我一半的时间都在调程序,所以想专门和你聊一聊。
如果你自认实战能力还不错。我建议你和我一样,从零开始搭建好项目后,在自己搭建的项目上,跟着课程讲解的顺序一点一点去实现。
当然,在这个过程中,我们会遇到很多错误,我想一个合格的程序员会一一解决出现的错误。**磨刀不误砍柴工这个跟Bug斗争的过程不也正是提高写代码调试代码的能力嘛。**
最后的程序,我大概用了近一个周才完成。当然不是全职调试,调程序的快乐不亲自体验是感受不到的,反正自己是快乐了。我印象最深的就是文件系统那里,在最后的调试测试过程中,执行到文件测试函数就会宕机,造成整个系统崩溃。
先前我一直认为是进程调度或者文件驱动那有问题,反复查看。最后才想到,是不是测试函数写错了?
果然仔细查看代码找到了0f写成了ff的问题。我总是特别相信“简单的代码不会出问题”一时大意导致自己折腾更久。希望你不要像我一样轻视“简单的代码”。同时强烈推荐你用GDB调试像我说的这种错误用GDB很快就能定位到。
我把自己的做的所有工作都通过[笔记](https://aeneag.xyz/virginOS)记录了下来。最后我还给系统添加了一个shell上的简易计算器主函数如下。思想很简单代码相信你很容易就能看懂
```c++
int cal_main(hand_t *hand)
{
//定义并初始化一些变量
int input = 1;
memset((void*)&calbuff, 0, sizeof(shellkbbuff_t));
int(*p[5])(int, int) = { 0, Add, Sub, Mul, Div };//函数指针数组
int kbcode;
while (1)//循环
{
cal_st:
menu();
printf(" 请选择:");
for(;;){//这个循环是获取键盘数据
kbcode = read_keyboard_code(*hand);
if(32 <= kbcode && 127 >= kbcode){
input = kbcode - 48;
gl_fl = input;
printf("%d\n", input);
if(!input)break;
if(input < 0 || input > 4){
cal_err:
printf("\n input err,please restart input !\n");
goto cal_st;
}
if (input >= 1 && input <= 4){
calc(p[input],hand);//计算函数
goto cal_st;
}
}
if(0x103 == kbcode){
goto cal_err;
}
}
break;
}
printf(" exit!");
return 0;
}
```
经历了种种挑战,我最终完成的效果演示视频如下,希望也能激励到正在学习的你。
[https://pic.aeneag.xyz/virginOS/virginOS.mp4](https://pic.aeneag.xyz/virginOS/virginOS.mp4)
视频中添加了开机动画。看起来简单的几秒动画实际是近240张序列帧图如果感兴趣的话可以在 **initldr/ldrkrl/graph.c** 中查看具体实现,在此,我要特别感谢我的朋友胖哥提供的图片支持。
另外我也添加了几个shell命令比如前面提到的简易计算器cal指令感兴趣的可以在app文件夹下查看具体实现代码。
当然这也只是我的阶段性成果。以后我有机会一定要实现进程那块的红黑树进程调度还有一些常用的shell命令。
## 此地一为别,孤蓬万里征
虽然课程的学习告一段落但对OS的热爱才刚刚开始此地一为别孤蓬万里征。
你我仍在路上。世上没有白走的路,有的话,也许多走几遍就能发现“隐藏宝藏”。我与这门课共度了两个月,期间一直对着代码废寝忘食地折腾。
**我觉得最大的认知改变就是视角的切换,以前更多是以一个使用者的角度去看系统,如今却能以一个设计实现者的角度去看系统。**
举个例子。不知道你是否写过驱动程序。如果有过这样的经历应该知道这会用到很多由内核提供的接口函数或者结构体比如最常用的file\_operations。写驱动是使用这些接口那么通过这门课我们却成为了提供这些接口的角色比如提供驱动中的drvstus\_t结构体等等。
最后送给大伙儿三点建议:
1.下定决心的事,要坚持完成,有始有终;
2.多思考,多做笔记,多动手;
3.多读书。
也祝愿你在这门课里收获属于自己的精彩!如果觉得我的分享还不错,希望点赞或者评论支持一下。