最近更新 | Last Updated
Prenote
NOTICE: This content is presented as
git diff.
更新记录(2026-09-17 13:39:38 +0000 | ddb6cfd7)
Summary
- Generated at:
2026-09-17 13:39:38 +0000 - Base commit:
ddb6cfd7 - Diff source:
c01a2d0a7eead0029396cce48742eea1d1c43b54..ddb6cfd7a51c67f7fb2a169b4d5a1e15e6e34dcf - Changed files:
6 - Total lines:
+461 / -59
Index
- src/学习与进步/计算机科学极简入门指南/操作系统/第六十七章:自旋锁与睡眠锁.md
+75 / -9 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十三章:进程间通信.md
+61 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十五章:临界区与原子操作.md
+82 / -10 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十八章:等待与通知.md
+81 / -9 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十六章:互斥锁.md
+80 / -9 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十四章:程序竞争.md
+82 / -9
Diffs
src/学习与进步/计算机科学极简入门指南/操作系统/第六十七章:自旋锁与睡眠锁.md
+75 / -9 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\227\213\351\224\201\344\270\216\347\235\241\347\234\240\351\224\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\227\213\351\224\201\344\270\216\347\235\241\347\234\240\351\224\201.md"
index 94a1a7f6..62a7a649 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\227\213\351\224\201\344\270\216\347\235\241\347\234\240\351\224\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\203\347\253\240\357\274\232\350\207\252\346\227\213\351\224\201\344\270\216\347\235\241\347\234\240\351\224\201.md"
@@ -1,21 +1,87 @@
-# 第六十七章:自旋锁与睡眠锁
+# 自旋锁与睡眠锁
+
+## 复习
+
+- 程序竞争:多条执行线同时读写共享数据,可能互相干扰
+- 临界区与原子操作:哪些代码必须表现得像不可分割的一步
+- 互斥锁:让同一时刻只有一个执行线进入临界区
## TL;DR
-- 等锁很短时可自旋;等待较久时应睡眠并让出 CPU。
+
+- 拿不到锁时,有两种等法:**原地重试(自旋)** 或 **睡下等待(睡眠)**
+- 自旋锁:一直占着 CPU 重试,适合临界区很短的情况
+- 睡眠锁:让出 CPU、等别人唤醒,适合等待较久的情况
+- 选哪种,取决于预计要等多久
## 正文
- **自旋锁**拿不到锁就反复检查,免去睡眠和唤醒成本,适合临界区极短且无法睡眠的场景。若持锁者要等待磁盘,自旋者只会白白烧掉 CPU。
- **睡眠锁**把等待者阻塞,释放锁时再唤醒。选择取决于预期等待时间和调度成本。
+ 锁的接口看似简单:拿不到就等。可“怎么等”,却大有讲究。同样是在门口等锁,有两种截然不同的姿态。
+
+### 自旋:原地打转
+
+ **自旋锁**(spinlock)的做法是:
+
+```text
+while (拿不到锁) {
+ // 什么都不做,继续试
+}
+```
+
+ 它一直占着 CPU,反复检查锁有没有被放开。好处是:
+
+- 不涉及上下文切换,**反应极快**
+- 一旦锁释放,几乎是立刻就抢到
+
+ 代价也很明显:等待期间它**一直在空转烧 CPU**。如果临界区很短,等一小会儿就轮到自己,这很划算;可如果需要等很久,那就是白白浪费。
+
+### 睡眠:让出 CPU
+
+ **睡眠锁**(sleeping lock)则温和得多:拿不到锁时,直接把自己标记为阻塞,交给内核,让出 CPU 去干别的;等锁被释放时,再由内核把它唤醒。
+
+ 这样一来,等待期间 CPU 可以去跑别的线程,不浪费。但代价是:**睡眠和唤醒都要做上下文切换**,开销比自旋大。
+
+### 怎么选
+
+ 两种等法,正好对应两种场景:
-**思考题**
-> 为什么单核上长时间自旋尤其糟糕?
+| | 自旋锁 | 睡眠锁 |
+| :--- | :--- | :--- |
+| 等待方式 | 原地重试,不让 CPU | 让出 CPU,等唤醒 |
+| 开销 | 不切换,但空转 | 要切换 |
+| 适合 | 临界区很短 | 等待较久 |
+
+ 一句话:**预计很快能拿到,就自旋;预计要等很久,就睡眠。**
+
+ 还有一个细节:在单核机器上,如果拿着锁的线程根本没法运行(比如它被挂起了),那么自旋的线程永远也等不到锁释放,只会一直空转;这时睡眠锁才靠谱。所以自旋锁多用在多核、且临界区极短的内核场景里。
+
+ **思考题**
+
+> 如果一个线程要等锁接近一秒钟,用自旋锁会发生什么?这一秒钟里,CPU 在做什么“有用的事”吗?
## 小结
-- 等待策略应匹配等待长度。
+
+### 知识点
+
+- 自旋锁:忙等,不切换,适合短临界区
+- 睡眠锁:阻塞并让出 CPU,适合长等待
+- 选择的依据是预计等待时间
+- 单核且锁可能长时间不可用时应避免自旋
+
+### 参考资料
+
+1. [Wikipedia(zh):自旋锁](https://zh.wikipedia.org/wiki/%E8%87%AA%E6%97%8B%E9%94%81):spinlock
+2. [Wikipedia(zh):信号量](https://zh.wikipedia.org/wiki/%E4%BF%A1%E5%8F%B7%E9%87%8F):睡眠与唤醒
### 思考题答案(仅供参考)
- 自旋者占着唯一 CPU,持锁者甚至可能得不到机会运行并释放锁。
+
+ 用自旋锁等接近一秒,意味着这个线程会占着 CPU 原地空转近一秒,反复检查一个暂时不会变的状态。这一秒里它没有做任何有用的事,纯粹浪费了一个 CPU 核心——如果别的可运行线程还排着队,就更亏。这种情况明显应该用睡眠锁:把自己挂起,让出 CPU,等锁释放时再被唤醒。所以“自旋适合短等、睡眠适合长等”,本质上是在“切换开销”和“空转浪费”之间选成本更低的那个。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十三章:进程间通信.md
+61 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241.md"
index 6f92fe61..c9af8453 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\211\347\253\240\357\274\232\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241.md"
@@ -1,35 +1,83 @@
-# 第六十三章:进程间通信
+# 进程间通信
## 复习
-- 线程共享同一地址空间,进程默认彼此隔离。
+- 多级反馈队列:不知道任务长短时,靠反馈自动调整优先级
+- 多核调度:任务分到多个 CPU 后还要处理负载和缓存亲和
+- 线程与并发:一个进程内可以有多条共享内存的执行线
## TL;DR
-- 进程间通信让隔离的程序交换数据或通知。
-- 管道、消息、信号和共享内存适合不同粒度的协作。
+- 进程之间内存隔离,互相看不到对方的数据
+- 要交换数据,得借助内核提供的专门通道
+- 常见方式:管道、消息、信号、共享内存
+- 各有取舍:共享内存最快,但要自己处理同步
## 正文
- 命令行中的管道把一个程序的输出接到另一个程序输入;消息队列保存一条条消息;信号适合传递简短的事件通知;**共享内存**让两个进程映射同一批物理页,传大量数据很快,但需要自行协调读写。
+ 上一章说,同一进程里的线程共享内存,交换数据很方便。可进程与进程之间是隔离的——这也是它们的优点:一个进程出错,不会直接改坏另一个进程的数据。
- 这些机制都通过内核建立边界和权限。它们不是让隔离消失,而是在隔离之间开一扇有规则的门。选择方式取决于数据量、是否要保留边界、是否需要异步通知。
+ 但隔离也带来麻烦:两个进程想交换数据,怎么办?
- 一旦多个执行者会碰同一份数据,新的麻烦立即出现:看似简单的加一,为什么会得到错误结果?
+### 为什么不能直接读写对方内存
-**思考题**
+ 每个进程都有自己独立的地址空间(后面会专门讲)。进程 A 眼里的地址 1000,和进程 B 眼里的地址 1000,很可能对应完全不同的物理内存。A 也没法凭一个地址,去访问 B 的数据。
-> 共享内存很快,为什么仍不能自动解决协作问题?
+ 所以,进程间通信(IPC,Inter-Process Communication)必须借助**内核**:由内核提供一条双方都能用的通道,数据经由这条通道传递。
+
+### 几种常见方式
+
+ 内核提供的通道有好几种,各有各的脾气:
+
+- **管道(pipe)**:一条单向的字节流,像一根水管。一端往里写,另一端从里读。适合把“前一个程序的输出”接到“后一个程序的输入”。
+- **消息队列**:一条条有边界的“消息”。每发一条,对方就收到一条,能保留消息之间的分界。
+- **信号(signal)**:一个简短的通知,用来“打断”对方,比如告诉它“该结束了”。它只传递很少的信息。
+- **共享内存**:由内核划出一块内存,让两个进程都能访问。数据不走内核中转,**速度最快**;但正因为大家都能直接读写,必须另外配一套同步机制,否则会互相踩脚。
+
+ 前三种都要经过内核搬运或转发;共享内存则让双方直接读写同一块地方,省去了搬运。
+
+### 怎么选
+
+| 方式 | 传递什么 | 速度 | 同步难度 |
+| :--- | :--- | :--- | :--- |
+| 管道 | 字节流 | 一般 | 低 |
+| 消息队列 | 有边界的消息 | 一般 | 低 |
+| 信号 | 简短通知 | 快 | 低 |
+| 共享内存 | 任意数据 | 最快 | 高 |
+
+ 一句话:**想省事就用管道或消息,想最快就用共享内存,但要额外操心同步。** 怎么在这两者之间取平衡,正是接下来几章要展开的。
+
+ 而“共享内存要同步”这件事,其实不只发生在进程之间——同一进程里的多个线程共享内存,也会撞上同样的麻烦。下一章,我们从最简单的一个例子看起:两个线程同时给一个数加一,为什么会加错?
+
+ **思考题**
+
+> 既然共享内存最快,为什么不让所有进程通信都用共享内存?多出来的是哪部分工作?
## 小结
-- IPC 为隔离进程提供受控通信方式。
-- 共享数据仍需要协调访问顺序。
+### 知识点
+
+- 进程地址空间互相隔离,无法直接访问对方数据
+- 进程间通信需要内核提供通道
+- 管道、消息、信号、共享内存各有取舍
+- 共享内存最快,但需要额外的同步
+
+### 参考资料
+
+1. [Wikipedia(zh):进程间通信](https://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1):IPC 的各种方式
+2. [Wikipedia(zh):管道](https://zh.wikipedia.org/wiki/%E7%AE%A1%E9%81%93_(Unix)):管道
+3. [Wikipedia(zh):共享内存](https://zh.wikipedia.org/wiki/%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98):共享内存
### 思考题答案(仅供参考)
- 两个进程可能在同一时刻读写同一位置;速度并不会规定谁先做哪一步。
+ 因为共享内存虽然快,却把“协调”这件事全丢给了使用者:多个进程同时读写同一块内存,必须自己保证它们不会互相覆盖、不会读到写了一半的数据。这就需要锁、信号量等一整套同步机制,写起来容易出错。管道和消息由内核替你把数据搬好、把边界划清,省心得多。所以选哪种,要看更在意速度还是更在意省事——工具没有绝对的好坏,只有是否合适。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十五章:临界区与原子操作.md
+82 / -10 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\344\270\264\347\225\214\345\214\272\344\270\216\345\216\237\345\255\220\346\223\215\344\275\234.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\344\270\264\347\225\214\345\214\272\344\270\216\345\216\237\345\255\220\346\223\215\344\275\234.md"
index 8d6074e5..b57dcbfa 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\344\270\264\347\225\214\345\214\272\344\270\216\345\216\237\345\255\220\346\223\215\344\275\234.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\224\347\253\240\357\274\232\344\270\264\347\225\214\345\214\272\344\270\216\345\216\237\345\255\220\346\223\215\344\275\234.md"
@@ -1,24 +1,96 @@
-# 第六十五章:临界区与原子操作
+# 临界区与原子操作
+
+## 复习
+
+- 线程与并发:一个进程内可以有多条共享内存的执行线
+- 进程间通信:进程之间靠管道、消息、信号或共享内存交换数据
+- 程序竞争:多条执行线同时读写共享数据,可能互相干扰
## TL;DR
-- 访问共享资源、不可被同时执行的代码称为临界区。
-- 原子操作表现得像不可再分的一步。
+- **临界区**:一段访问共享数据的代码,同一时刻只允许一个执行线进入
+- **原子操作**:硬件保证“不可被中途打断”的操作
+- 保证“同一时刻只有一个进入临界区”,叫**互斥**(mutual exclusion)
+- 用原子操作,可以搭出实现互斥的锁
## 正文
- 更新共享计数器的“读—改—写”是**临界区**。CPU 提供比较并交换、原子加等原子操作:别的核心无法在它中间看到半完成状态。它们是更高层同步工具的地基。
+ 上一章我们看到,加一被拆成读、改、写三步,两条执行线一交错,就丢数据。要根治,得划出一条界线:某段代码,同一时刻只许一个人进。
+
+### 临界区
+
+ 这段“必须独占”的代码,叫**临界区**(critical section)。它通常正是那些访问共享数据的代码,比如“读—改—写某个全局变量”。
+
+ 我们要的规矩只有一条:**同一时刻,最多只有一个执行线在临界区里。** 这条规矩叫**互斥**(mutual exclusion)。其余的线程要么在门口等,要么先去做别的事。
+
+```text
+线程 A:│ 进入临界区 │ 执行 │ 离开 │
+线程 B: │ 进入临界区 │ 执行 │ 离开 │
+```
+
+ 只要这条规矩守住,临界区里的“读—改—写”就再也不会被插入,丢失更新也就不发生了。
+
+### 原子操作
+
+ 可“划出临界区”本身,也需要一个不含糊的工具。这正是**原子操作**(atomic operation)的用武之地。
+
+ 原子操作由硬件提供,一旦开始就**保证一口气做完**,中间绝不会被别的执行线插进来——要么没做,要么全做完,没有“做了一半”的状态。
+
+ 常见的原子操作有:
+
+- **交换**:把寄存器和内存里的值对调
+- **测试并设置**:读出旧值,同时把它设成 1
+- **比较并交换**:只有当内存里的值等于预期时,才把它换成新值
+
+ 它们看似简单,却是搭所有同步工具的“地基”。
+
+### 用原子操作搭一把锁
+
+ 有了原子操作,实现互斥就有了思路。以“测试并设置”为例,我们可以用一个标志位表示锁:
- 原子操作只解决一次小动作;若临界区有多步,仍需一种让进入者排队的规则。
+- 想进临界区,就“测试并设置”这个标志位
+- 如果测出来的旧值是 0(没人占),就说明抢到了锁,可以进去
+- 如果旧值是 1(已被占),说明别人正拿着,只能等
-**思考题**
-> 原子加为什么能避免丢失更新?
+ 因为整个“测试 + 设置”是一步原子操作,两个线程不可能同时抢到——总有一个先拿到,另一个只能看到 1。
+
+ 抢到锁的一方进入临界区,办完事再把标志位设回 0,放别人进来。如此,临界区就被稳稳地保护起来了。
+
+### 忙等的代价
+
+ 上面这种“拿不到就反复重试”的等待方式,叫**忙等**(busy waiting):线程一直占着 CPU 空转。
+
+ 能拿到就还好,可如果锁被占很久,忙等就纯属浪费。怎样等得更聪明?下一章,我们把这套机制封装成一个好用的接口——**互斥锁**,并讨论它该怎样等待。
+
+ **思考题**
+
+> “测试并设置”为什么必须是原子操作?如果把它拆成“先测试、再设置”两步,两个线程同时想抢锁,会发生什么?
## 小结
-- 原子性隐藏中间状态,是同步的基本积木。
+
+### 知识点
+
+- 临界区:访问共享数据、必须独占执行的代码
+- 互斥:同一时刻只有一个执行线在临界区
+- 原子操作:硬件保证不可打断,常见有交换、测试并设置、比较并交换
+- 用原子操作可以搭出锁
+
+### 参考资料
+
+1. [Wikipedia(zh):临界区](https://zh.wikipedia.org/wiki/%E4%B8%B4%E7%95%8C%E5%8C%BA):critical section
+2. [Wikipedia(zh):互斥锁](https://zh.wikipedia.org/wiki/%E4%BA%92%E6%96%A5%E9%94%81):mutex
+3. [Wikipedia(zh):原子操作](https://zh.wikipedia.org/wiki/%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C):atomic operation
### 思考题答案(仅供参考)
- 每次加法完整完成后,下一次才读取新的结果。
+
+ 如果拆成两步,两个线程可能都先“测试”,都看到标志位是 0,都以为没人占,于是都去“设置”并进入临界区——互斥就破了。把“测试并设置”合成一步原子操作,硬件保证同一时刻只有一个线程完成它,两个线程必然分成先后:先完成的抢到锁,后完成的看到 1,只能等。所以原子性是这条防线成立的关键。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十八章:等待与通知.md
+81 / -9 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\253\347\253\240\357\274\232\347\255\211\345\276\205\344\270\216\351\200\232\347\237\245.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\253\347\253\240\357\274\232\347\255\211\345\276\205\344\270\216\351\200\232\347\237\245.md"
index 310b7c3e..1a1ca51c 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\253\347\253\240\357\274\232\347\255\211\345\276\205\344\270\216\351\200\232\347\237\245.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\253\347\253\240\357\274\232\347\255\211\345\276\205\344\270\216\351\200\232\347\237\245.md"
@@ -1,21 +1,93 @@
-# 第六十八章:等待与通知
+# 等待与通知
+
+## 复习
+
+- 临界区与原子操作:哪些代码必须表现得像不可分割的一步
+- 互斥锁:让同一时刻只有一个执行线进入临界区
+- 自旋锁与睡眠锁:等待锁时应该原地重试还是让出 CPU
## TL;DR
-- 条件变量让线程在条件不满足时睡眠,并在状态变化后被通知。
+
+- 光有锁还不够:有时线程要等“某个条件”成立,而条件不成立就不能往下走
+- **条件变量**:让线程在条件不满足时睡下,条件满足时被唤醒
+- 它必须和锁配合使用,否则可能“错过唤醒”
+- 被唤醒后通常要用循环重新检查条件
## 正文
- 锁只能回答“谁能进来”,不能回答“现在有没有数据”。条件变量把两件事配合起来:线程持锁检查条件;不满足时原子地释放锁并睡眠;另一线程改变状态后通知等待者,等待者醒来重新检查。
- 必须重新检查,因为醒来不等于条件必然仍成立,其他线程可能已先一步改变状态。
+ 锁解决了“同一时刻只能一个进”的问题。可还有一类等待,锁管不了:线程要等到**某个条件成立**,才能继续。
+
+### 锁住也办不到的事
+
+ 想象生产者—消费者里的消费者:它要取走数据,可缓冲区是空的。这时它不能往下走,但也**不能一直攥着锁等**——那会让生产者连放数据的机会都没有。
+
+ 于是需求变成了:**条件不满足时,先放开锁睡下;等条件满足了,再醒过来。**
+
+### 条件变量
+
+ 这个工具叫**条件变量**(condition variable)。它通常提供两个动作:
+
+- `wait`:睡下,同时**释放锁**,让别人能进来改变条件
+- `signal`:唤醒一个正在等待的线程
+
+ 典型用法是这样的:
+
+```text
+lock()
+while (条件不成立) {
+ wait(锁) // 睡下并放开锁;被唤醒后重新拿到锁
+}
+// 条件成立,办事
+unlock()
+```
+
+ 注意 `wait` 的一个巧妙之处:它一口气做了两件事——把当前线程睡下,同时把锁放开。这样,别的线程才进得来、把条件改成立,然后 `signal` 把你叫醒。
+
+### 为什么要用循环
+
+ 被唤醒之后,为什么是用 `while` 重新检查条件,而不是 `if`?
+
+ 因为**被唤醒,不等于条件一定成立**:
-**思考题**
-> 为什么等待前要先持有同一把锁?
+- 从你被唤醒到重新拿到锁,可能又有别人抢先改变了条件
+- 可能有多个线程被一次唤醒“惊”到,但只有一个人能如愿
+
+ 所以稳妥的做法是:醒来后**再看一眼条件**;不满足,就接着睡。这个“再看一眼”的循环,是条件变量的标准姿势。
+
+### 容易踩的坑:错过唤醒
+
+ 条件变量必须和锁一起用,否则会出错。设想:你检查条件(不成立)→ 还没来得及睡下 → 另一个线程改变了条件并 `signal` → 你这时才睡下。
+
+ 结果,那次 `signal` 白白浪费,你睡下去却再也没人叫醒,程序卡住。这类问题叫**错过唤醒**。把“检查条件”和“睡下”放在同一把锁的保护里,就能堵住这个缝。
+
+ **思考题**
+
+> 如果被唤醒后只用 `if` 检查一次条件就往下走,可能出什么错?为什么 `while` 更安全?
## 小结
-- 条件变量协调状态变化,不取代互斥锁。
+
+### 知识点
+
+- 条件变量用于等待“某个条件成立”
+- `wait` 睡下并释放锁,`signal` 唤醒等待者
+- 必须配合锁使用,避免错过唤醒
+- 唤醒后要用循环重新检查条件
+
+### 参考资料
+
+1. [Wikipedia(zh):条件变量](https://zh.wikipedia.org/wiki/%E6%9D%A1%E4%BB%B6%E5%8F%98%E9%87%8F):condition variable
+2. [Wikipedia(zh):监视器](https://zh.wikipedia.org/wiki/%E7%9B%91%E8%A7%86%E5%99%A8_(%E7%A8%8B%E5%BA%8F%E5%90%8C%E6%AD%A5)):条件变量与锁的组合
### 思考题答案(仅供参考)
- 锁让检查条件与开始等待之间没有空隙,避免错过通知。
+
+ 用 `if` 检查一次就往下走,可能在你被唤醒、重新拿到锁的这段时间里,条件又被别的线程改回去了;或者一次唤醒惊动了多个线程,只有一个人满足条件,其他人却误以为成立。`while` 会在醒来后重新检查,条件不满足就继续睡,因此更安全。一句话:**“被叫醒”只是提示,条件到底成不成立,还得自己再看一眼。**
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十六章:互斥锁.md
+80 / -9 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\344\272\222\346\226\245\351\224\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\344\272\222\346\226\245\351\224\201.md"
index fc2f642f..4f99e1db 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\344\272\222\346\226\245\351\224\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\205\255\347\253\240\357\274\232\344\272\222\346\226\245\351\224\201.md"
@@ -1,21 +1,92 @@
-# 第六十六章:互斥锁
+# 互斥锁
+
+## 复习
+
+- 进程间通信:进程之间靠管道、消息、信号或共享内存交换数据
+- 程序竞争:多条执行线同时读写共享数据,可能互相干扰
+- 临界区与原子操作:哪些代码必须表现得像不可分割的一步
## TL;DR
-- 互斥锁保证同一时刻只有一个执行者进入临界区。
+
+- **互斥锁**:进入临界区前加锁,离开时解锁
+- 加锁失败就等待,直到持有者释放
+- 它把“互斥”这件麻烦事封装成一个简单接口
+- 用锁要小心:忘记解锁,别人就永远进不来
## 正文
- 线程进入临界区前请求锁,完成后释放锁。锁已被占用时,后来者不能继续访问共享数据。原子“测试并设置”让两个线程不会同时以为自己拿到了锁。
- 锁必须在所有路径上释放,否则其他线程会永久等待;而锁保护范围过大又会不必要地降低并发。
+ 上一章的临界区和原子操作,原理都对,可用起来还是麻烦。现实中,没人愿意在每个临界区门口手写一套“测试并设置”。于是人们把它封装成一个接口——**互斥锁**(mutex)。
+
+### 一个简单的接口
+
+ 互斥锁只提供两个动作:
+
+- `lock`:尝试加锁。成功就进入临界区;失败就等待
+- `unlock`:解锁,让出临界区
+
+ 用法非常直白:
+
+```text
+lock()
+ // 临界区:访问共享数据
+unlock()
+```
+
+ 锁只有“被持有”和“空闲”两种状态。谁先 `lock` 成功,谁就拿着锁;其余的人一律在 `lock` 处排队,直到持有者 `unlock`。
+
+### 锁替我们做了什么
+
+ 别看接口简单,它背后替我们处理了一堆麻烦:
+
+- 用原子操作抢锁,保证不会两个人同时进入
+- 拿不到时如何等待、如何被唤醒
+- 释放时如何把锁交给下一个等待者
+
+ 我们只要记得“进临界区就加锁、出临界区就解锁”,其余细节都被锁藏起来了。这又是**加一层**:把容易写错的同步细节,包装成一个不会用错的按钮。
+
+### 锁的粒度
+
+ 锁保护的范围,叫**粒度**。粒度要拿捏:
-**思考题**
-> 忘记释放锁为什么像把门钥匙带走?
+- 锁得**太宽**(把很多不相关的代码都圈进去),大家挤在一把锁上,并发度下降,等于白瞎了多核
+- 锁得**太窄**(只锁住其中一小部分),可能漏保护了共享数据,错误照旧
+
+ 一个常见毛病叫**粗粒度锁**:图省事,用一把大锁保护几乎所有共享数据。程序是安全了,但多个线程几乎串行,性能很差。好的做法是把大锁拆成若干小锁,各管一摊——不过这又容易引出新的麻烦,后面讲死锁时会看到。
+
+### 忘记解锁会怎样
+
+ 锁用起来简单,但有一个致命陷阱:**忘记解锁**。
+
+ 一旦某个线程拿了锁却忘了还,所有等在 `lock` 处的线程就永远等下去,整个程序卡死。所以,实际编程里通常用一套“成对出现”的写法:加了锁,就必须保证在任何路径下都会解锁,哪怕中途出错。
+
+ **思考题**
+
+> 如果一把锁保护的范围里,又调用了另一个也需要同一把锁的函数,会发生什么?这和“忘记解锁”有什么共同点?
## 小结
-- 互斥锁把临界区串行化。
+
+### 知识点
+
+- 互斥锁提供 `lock` 和 `unlock`
+- 锁把原子操作、等待和唤醒封装起来
+- 锁的粒度:太宽降低并发,太窄保护不全
+- 忘记解锁会导致其他线程永远等待
+
+### 参考资料
+
+1. [Wikipedia(zh):互斥锁](https://zh.wikipedia.org/wiki/%E4%BA%92%E6%96%A5%E9%94%81):mutex
+2. [Wikipedia(zh):锁](https://zh.wikipedia.org/wiki/%E9%94%81_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)):锁的概念
### 思考题答案(仅供参考)
- 后续线程都会看到锁仍被占用,无法进入受保护的区域。
+
+ 如果同一把锁在已经持有的情况下又被请求,就形成“自己等自己”:持有者等一个只有它自己能释放的锁,于是永远等下去。这和“忘记解锁”的共同点是——锁都不会再被放开,等待者全都卡住。它们的区别只是:忘记解锁是根本没还;重复加锁是还想再借一次,却把门从里面反锁了。不少锁提供了“可重入”版本来缓解后者,但设计上仍应尽量避免这种嵌套。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十四章:程序竞争.md
+82 / -9 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\347\253\236\344\272\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\347\253\236\344\272\211.md"
index c560e036..b101fa86 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\347\253\236\344\272\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\347\253\236\344\272\211.md"
@@ -1,24 +1,97 @@
-# 第六十四章:程序竞争
+# 程序竞争
+
+## 复习
+
+- 多核调度:任务分到多个 CPU 后还要处理负载和缓存亲和
+- 线程与并发:一个进程内可以有多条共享内存的执行线
+- 进程间通信:共享内存最快,但需要自己处理同步
## TL;DR
-- 多个执行者交错读写共享数据时,结果可能取决于偶然顺序。
+- 多条执行线同时读写同一份数据,可能互相干扰
+- “读取—修改—写回”不是一步完成的,中途可能被打断
+- 结果取决于执行顺序的现象,叫**竞态条件**(程序竞争)
+- 它难以复现,是并发程序里最经典的难题
## 正文
- `count = count + 1` 在机器里至少包括读出、加一、写回。两个线程同时做它,可能都读到 0、都写回 1,最后丢掉一次更新。这种依赖时序而出现的错误叫**竞争条件**。
+ 先看一个让人想不通的实验。
+
+ 我们开两个线程,让它们各自把同一个变量 `count` 加 1000 次。按理说,最后 `count` 应该是 2000。可实际跑起来,结果常常是 1000 多、1900 多,甚至每次都不一样。
+
+ 加个加法而已,怎么会加错?
+
+### 加一,其实是三步
+
+ 问题出在:`count = count + 1` 这行代码,对计算机来说并不是“一步”完成的,而是三步:
+
+1. **读**:把 `count` 的值从内存取到寄存器
+2. **改**:在寄存器里加一
+3. **写**:把新值写回内存
+
+ 单线程时,这三步顺顺当当连在一起。可两个线程同时跑,就可能交错。
+
+### 交错是怎样丢数据的
+
+ 假设 `count` 现在是 5。两个线程都要加一:
+
+```text
+线程 A:读 count → 5
+线程 B:读 count → 5 ← B 也读到了 5
+线程 A:改 → 6
+线程 B:改 → 6 ← B 基于旧的 5 得到 6
+线程 A:写回 → count = 6
+线程 B:写回 → count = 6 ← 各写各的,等于只加了一次
+```
+
+ 两次“加一”,本该变成 7,结果却是 6。因为 A 和 B 都基于同一个旧值 5 计算,后来者把前者的结果覆盖了。这就是**丢失更新**。
+
+### 竞态条件
+
+ 这种“结果取决于谁先谁后”的现象,叫**竞态条件**(race condition);由此引发的、难以察觉的冲突,常被形象地称为**程序竞争**。
- 问题不在“线程太快”,而在一项逻辑动作被拆成了多步。要修复它,必须让某些片段对其他线程看起来不可插入。
+ 它最讨厌的地方是**难以复现**:
-**思考题**
-> 两个线程各加一次,结果为何可能是 1?
+- 大多数时候顺序刚好错开,运行正常
+- 偶尔交错到坏时序,才冒一次错
+- 在单核上几乎测不出来,一上多核就出问题
+
+ 于是它成了并发程序里的“幽灵”:测试时好好的,上线后偶发错误,还极难定位。
+
+### 出路:别让关键几步被打断
+
+ 根源很清楚:两个线程可以随意穿插进对方的三步中间。
+
+ 那么,如果我们能划定一段代码,**保证同一时刻只有一个线程能执行它**,问题不就解决了吗?这段“必须独占执行”的代码,就是下一章的**临界区**。
+
+ **思考题**
+
+> 如果 `count = count + 1` 换成一条“读取、加一、写回”合为一步的原子指令,两个线程各加 1000 次还会出错吗?为什么?
## 小结
-- 竞争条件来自共享状态和可交错步骤。
+### 知识点
+
+- 加一其实是读、改、写三步,可能被打断
+- 交错执行会导致丢失更新
+- 竞态条件:结果依赖执行顺序
+- 竞态条件难以复现,是并发程序的经典难题
+
+### 参考资料
+
+1. [Wikipedia(zh):竞态条件](https://zh.wikipedia.org/wiki/%E7%AB%9E%E6%80%81%E6%9D%A1%E4%BB%B6):race condition
+2. [Wikipedia(zh):丢失更新](https://zh.wikipedia.org/wiki/%E4%B8%A2%E5%A4%B1%E6%9B%B4%E6%96%B0):lost update
### 思考题答案(仅供参考)
- 两者可能先后读到同一个旧值,再覆盖写回相同的新值。
+
+ 不会出错。如果“读取、加一、写回”被硬件保证为不可分割的一步,那么两个线程的加法就会一个接一个地完成,不会出现“都读到旧值”的交错,最终一定是 2000。这也正是下一章要讲的“原子操作”的思路:把容易出错的几步,合成一个不可打断的整体。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
更新记录(2026-09-17 13:36:31 +0000 | c01a2d0a)
Summary
- Generated at:
2026-09-17 13:36:31 +0000 - Base commit:
c01a2d0a - Diff source:
81e4d856e3ceddbe981e2fcbab03e1598647402d..c01a2d0a7eead0029396cce48742eea1d1c43b54 - Changed files:
27 - Total lines:
+81 / -81
Index
- src/学习与进步/计算机科学极简入门指南/操作系统/第五十一章:内核态与用户态.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十七章:调度要解决什么.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十三章:程序如何变成进程.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十九章:时间片与优先级调度.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十二章:系统调用.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十五章:进程控制块与进程状态.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十八章:先来先服务与最短任务优先.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十六章:上下文切换.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十四章:进程的创建与结束.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十章:操作系统是什么.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十一章:多核调度(进阶).md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十二章:线程与并发.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十章:多级反馈队列(进阶).md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第四十九章:引导程序与内核加载.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/操作系统/第四十八章:按下电源:复位与固件.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十七章:名字、标签与地址.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十九章:高级语言:再加一层.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十八章:汇编器.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十六章:用汇编语言指挥计算机.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十一章:分支与循环.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十七章:没有操作系统的程序.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十三章:函数调用与运行栈.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十二章:函数.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十五章:从源代码到可执行文件.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十六章:编译与解释.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十四章:程序在内存里的样子.md
+3 / -3 - src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十章:变量、类型与表达式.md
+3 / -3
Diffs
src/学习与进步/计算机科学极简入门指南/操作系统/第五十一章:内核态与用户态.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
index fc10bd68..265453a9 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
@@ -2,9 +2,9 @@
## 复习
-- 操作系统是资源的管理者和抽象的提供者
-- 内核常驻内存,程序通过它请求服务
-- 内核权力很大,不能任由普通程序指挥
+- 按下电源:复位与固件:CPU 从约定位置开始执行,固件接过控制权
+- 引导程序与内核加载:引导程序把内核装入内存,内核初始化后接手管理
+- 操作系统是什么:操作系统是资源的管理者和抽象提供者
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十七章:调度要解决什么.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
index 34693908..5e741ae0 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
@@ -2,9 +2,9 @@
## 复习
-- 上下文切换让 CPU 能在多个进程间来回
-- 进程有运行、就绪、阻塞三种状态
-- 就绪队列里排着许多“只差 CPU”的进程
+- 进程的创建与结束:父子进程、退出状态和资源回收
+- 进程控制块与进程状态:内核在哪里记录进程,以及三种状态的含义
+- 上下文切换:保存一个进程的现场,再恢复另一个
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十三章:程序如何变成进程.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
index cc48ca69..bcf464c1 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
@@ -2,9 +2,9 @@
## 复习
-- 操作系统是资源的管理者和抽象提供者
-- 用户程序通过系统调用请求内核服务
-- 内核要管理的,是一个又一个“正在运行的程序”
+- 操作系统是什么:操作系统是资源的管理者和抽象提供者
+- 内核态与用户态:为什么普通程序不能随意执行危险操作
+- 系统调用:用户程序怎样安全地请求内核服务
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十九章:时间片与优先级调度.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
index 9f2db3a5..0071ff54 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
@@ -2,9 +2,9 @@
## 复习
-- FCFS 简单,但长任务会堵住后面的人
-- SJF 平均等待最短,却不知道运行时间、还会饿死长任务
-- 现实需要兼顾“响应快”和“分轻重”
+- 上下文切换:保存一个进程的现场,再恢复另一个
+- 调度要解决什么:响应、吞吐、公平和优先级之间的矛盾
+- 先来先服务与最短任务优先:简单调度为何会出现等待和饥饿
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十二章:系统调用.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
index ede297ff..1c09b1ee 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
@@ -2,9 +2,9 @@
## 复习
-- CPU 分为内核态与用户态,界线由硬件保证
-- 用户程序要进入内核,必须经过受控入口
-- 系统调用就是其中的一类入口
+- 引导程序与内核加载:引导程序把内核装入内存,内核初始化后接手管理
+- 操作系统是什么:操作系统是资源的管理者和抽象提供者
+- 内核态与用户态:为什么普通程序不能随意执行危险操作
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十五章:进程控制块与进程状态.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
index 26893908..6a88f773 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
@@ -2,9 +2,9 @@
## 复习
-- 进程由已有进程创建,形成一棵进程树
-- 进程结束时留下退出状态,等待父进程回收
-- 内核要管理许多进程,必须清楚记得每一个
+- 系统调用:用户程序怎样安全地请求内核服务
+- 程序如何变成进程:区分静态的程序文件和运行中的进程
+- 进程的创建与结束:父子进程、退出状态和资源回收
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十八章:先来先服务与最短任务优先.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
index 06ebd9f8..36ad0412 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
@@ -2,9 +2,9 @@
## 复习
-- 调度要决定“选谁”和“跑多久”
-- 目标之间彼此冲突:响应、吞吐、公平、优先级
-- 先看两种最朴素的选人办法
+- 进程控制块与进程状态:内核在哪里记录进程,以及三种状态的含义
+- 上下文切换:保存一个进程的现场,再恢复另一个
+- 调度要解决什么:响应、吞吐、公平和优先级之间的矛盾
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十六章:上下文切换.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
index 6fc7e04d..553c3d47 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
@@ -2,9 +2,9 @@
## 复习
-- 内核用 PCB 记录每个进程的信息与状态
-- 进程分为运行、就绪、阻塞三种状态
-- 多个就绪进程要轮流使用同一个 CPU
+- 程序如何变成进程:区分静态的程序文件和运行中的进程
+- 进程的创建与结束:父子进程、退出状态和资源回收
+- 进程控制块与进程状态:内核在哪里记录进程,以及三种状态的含义
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十四章:进程的创建与结束.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
index 0a60183e..bfe5ca0a 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
@@ -2,9 +2,9 @@
## 复习
-- 程序是静态文件,进程是正在运行的程序
-- 内核把程序装入内存,建立地址空间,标记为就绪
-- 进程不会凭空出现,也不会凭空消失
+- 内核态与用户态:为什么普通程序不能随意执行危险操作
+- 系统调用:用户程序怎样安全地请求内核服务
+- 程序如何变成进程:区分静态的程序文件和运行中的进程
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第五十章:操作系统是什么.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
index 7b8daeaf..a3c9d9cc 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
@@ -2,9 +2,9 @@
## 复习
-- 固件、引导程序、内核层层接力,把机器唤醒
-- 内核初始化后,开始接手管理机器
-- 之前裸机程序遇到的困难,正等着它来处理
+- 没有操作系统的程序:裸机程序在装载、设备和多程序共存上的困难
+- 按下电源:复位与固件:CPU 从约定位置开始执行,固件接过控制权
+- 引导程序与内核加载:引导程序把内核装入内存,内核初始化后接手管理
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第六十一章:多核调度(进阶).md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
index 8421563f..0d10c53b 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -4,9 +4,9 @@
## 复习
-- 调度决定谁上 CPU、跑多久
-- 时间片、优先级、老化共同平衡响应与公平
-- 到目前为止,我们默认只有一个 CPU
+- 先来先服务与最短任务优先:简单调度为何会出现等待和饥饿
+- 时间片与优先级调度:让多个程序都感觉自己被及时响应
+- 多级反馈队列:不知道任务长短时,靠反馈自动调整优先级
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第六十二章:线程与并发.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
index b601e879..f95a3b0d 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
@@ -2,9 +2,9 @@
## 复习
-- 进程是正在运行的程序,拥有独立的地址空间
-- 内核通过调度让多个进程轮流使用 CPU
-- 进程之间彼此隔离,互不干扰
+- 时间片与优先级调度:让多个程序都感觉自己被及时响应
+- 多级反馈队列:不知道任务长短时,靠反馈自动调整优先级
+- 多核调度:任务分到多个 CPU 后还要处理负载和缓存亲和
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第六十章:多级反馈队列(进阶).md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
index ad9759aa..f90e8408 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -4,9 +4,9 @@
## 复习
-- 时间片保证人人轮得到,优先级保证重要的先跑
-- 但优先级会带来饥饿,需要老化来补救
-- 调度器往往事先并不知道每个任务要跑多久
+- 调度要解决什么:响应、吞吐、公平和优先级之间的矛盾
+- 先来先服务与最短任务优先:简单调度为何会出现等待和饥饿
+- 时间片与优先级调度:让多个程序都感觉自己被及时响应
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第四十九章:引导程序与内核加载.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
index cd0f237f..18cbe803 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
@@ -2,9 +2,9 @@
## 复习
-- 上电复位后,CPU 从固定地址开始执行
-- 固件负责自检并找到启动设备
-- 固件把控制权交给启动设备上的引导程序
+- 编译与解释:程序变成机器指令的两条基本道路
+- 没有操作系统的程序:裸机程序在装载、设备和多程序共存上的困难
+- 按下电源:复位与固件:CPU 从约定位置开始执行,固件接过控制权
## TL;DR
src/学习与进步/计算机科学极简入门指南/操作系统/第四十八章:按下电源:复位与固件.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
index 92157592..df71cd38 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
@@ -2,9 +2,9 @@
## 复习
-- 裸机程序必须自己解决装载、设备和多程序共存
-- 这些麻烦需要一个管理者来统一处理
-- 现在,我们从头看看这位管理者是怎样登场的
+- 从源代码到可执行文件:编译、汇编和链接的完整流水线
+- 编译与解释:程序变成机器指令的两条基本道路
+- 没有操作系统的程序:裸机程序在装载、设备和多程序共存上的困难
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十七章:名字、标签与地址.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\345\220\215\345\255\227\343\200\201\346\240\207\347\255\276\344\270\216\345\234\260\345\235\200.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\345\220\215\345\255\227\343\200\201\346\240\207\347\255\276\344\270\216\345\234\260\345\235\200.md"
index 259d72a5..ae0bb284 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\345\220\215\345\255\227\343\200\201\346\240\207\347\255\276\344\270\216\345\234\260\345\235\200.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\270\203\347\253\240\357\274\232\345\220\215\345\255\227\343\200\201\346\240\207\347\255\276\344\270\216\345\234\260\345\235\200.md"
@@ -2,9 +2,9 @@
## 复习
-- 助记符让机器指令变得可读
-- 汇编几乎与机器指令一一对应
-- 但地址、寄存器仍然要我们手工安排
+- 中断系统:中断让 CPU 响应外设请求,并在保存和恢复现场后继续执行程序
+- 第一次呼吸:把 CPU、存储器、总线和外设合起来,让完整计算机自动运行
+- 用汇编语言指挥计算机:用助记符代替难读的二进制机器指令
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十九章:高级语言:再加一层.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\271\235\347\253\240\357\274\232\351\253\230\347\272\247\350\257\255\350\250\200\357\274\232\345\206\215\345\212\240\344\270\200\345\261\202.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\271\235\347\253\240\357\274\232\351\253\230\347\272\247\350\257\255\350\250\200\357\274\232\345\206\215\345\212\240\344\270\200\345\261\202.md"
index aa6cbecc..1b550565 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\271\235\347\253\240\357\274\232\351\253\230\347\272\247\350\257\255\350\250\200\357\274\232\345\206\215\345\212\240\344\270\200\345\261\202.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\344\271\235\347\253\240\357\274\232\351\253\230\347\272\247\350\257\255\350\250\200\357\274\232\345\206\215\345\212\240\344\270\200\345\261\202.md"
@@ -2,9 +2,9 @@
## 复习
-- 汇编用助记符书写指令,几乎与硬件一一对应
-- 标签和名字让我们不再手工数地址
-- 汇编器把汇编翻译成机器码
+- 用汇编语言指挥计算机:用助记符代替难读的二进制机器指令
+- 名字、标签与地址:用名字和标签引用数据与跳转目标,不再手工数地址
+- 汇编器:通过两遍扫描,把符号汇编成机器码
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十八章:汇编器.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\346\261\207\347\274\226\345\231\250.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\346\261\207\347\274\226\345\231\250.md"
index 8ee12194..fae4f3a3 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\346\261\207\347\274\226\345\231\250.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\253\347\253\240\357\274\232\346\261\207\347\274\226\345\231\250.md"
@@ -2,9 +2,9 @@
## 复习
-- 汇编用助记符书写机器指令
-- 标签是地址的别名,让代码好读好改
-- 机器只认地址和比特,名字必须被翻译
+- 第一次呼吸:把 CPU、存储器、总线和外设合起来,让完整计算机自动运行
+- 用汇编语言指挥计算机:用助记符代替难读的二进制机器指令
+- 名字、标签与地址:用名字和标签引用数据与跳转目标,不再手工数地址
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第三十六章:用汇编语言指挥计算机.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\255\347\253\240\357\274\232\347\224\250\346\261\207\347\274\226\350\257\255\350\250\200\346\214\207\346\214\245\350\256\241\347\256\227\346\234\272.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\255\347\253\240\357\274\232\347\224\250\346\261\207\347\274\226\350\257\255\350\250\200\346\214\207\346\214\245\350\256\241\347\256\227\346\234\272.md"
index f893a9e9..67f114e0 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\255\347\253\240\357\274\232\347\224\250\346\261\207\347\274\226\350\257\255\350\250\200\346\214\207\346\214\245\350\256\241\347\256\227\346\234\272.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\344\270\211\345\215\201\345\205\255\347\253\240\357\274\232\347\224\250\346\261\207\347\274\226\350\257\255\350\250\200\346\214\207\346\214\245\350\256\241\347\256\227\346\234\272.md"
@@ -2,9 +2,9 @@
## 复习
-- 指令是机器能执行的一条命令,由操作码和操作数组成
-- 程序是一串按顺序执行的指令,PC 保存下一条指令的地址
-- CPU 循环取指、译码、执行,机器已经能自己往前跑
+- 输入输出系统:I/O 接口连接计算机与外设,支持查询、中断和 DMA 三种方式
+- 中断系统:中断让 CPU 响应外设请求,并在保存和恢复现场后继续执行程序
+- 第一次呼吸:把 CPU、存储器、总线和外设合起来,让完整计算机自动运行
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十一章:分支与循环.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\200\347\253\240\357\274\232\345\210\206\346\224\257\344\270\216\345\276\252\347\216\257.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\200\347\253\240\357\274\232\345\210\206\346\224\257\344\270\216\345\276\252\347\216\257.md"
index 62fcdf63..9d705e58 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\200\347\253\240\357\274\232\345\210\206\346\224\257\344\270\216\345\276\252\347\216\257.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\200\347\253\240\357\274\232\345\210\206\346\224\257\344\270\216\345\276\252\347\216\257.md"
@@ -2,9 +2,9 @@
## 复习
-- 变量是给存储起的名字,类型决定它怎么解释
-- 表达式是一棵运算树,按优先级依次求值
-- 目前写的程序都还是一条直路,从头走到尾
+- 汇编器:通过两遍扫描,把符号汇编成机器码
+- 高级语言:再加一层:从“控制机器”转向“描述问题”
+- 变量、类型与表达式:名字如何代表数据,表达式如何变成运算
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十七章:没有操作系统的程序.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\203\347\253\240\357\274\232\346\262\241\346\234\211\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\347\250\213\345\272\217.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\203\347\253\240\357\274\232\346\262\241\346\234\211\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\347\250\213\345\272\217.md"
index 49115aea..1620d84c 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\203\347\253\240\357\274\232\346\262\241\346\234\211\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\347\250\213\345\272\217.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\203\347\253\240\357\274\232\346\262\241\346\234\211\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\347\250\213\345\272\217.md"
@@ -2,9 +2,9 @@
## 复习
-- 程序要经过编译、汇编、链接,变成可执行文件
-- 可执行文件还要被“加载”进内存才能运行
-- 但“谁来加载、谁来管理”一直没有交代
+- 程序在内存里的样子:代码区、数据区、栈和堆的初步全景
+- 从源代码到可执行文件:编译、汇编和链接的完整流水线
+- 编译与解释:程序变成机器指令的两条基本道路
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十三章:函数调用与运行栈.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\211\347\253\240\357\274\232\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\350\277\220\350\241\214\346\240\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\211\347\253\240\357\274\232\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\350\277\220\350\241\214\346\240\210.md"
index 02bac0fe..66b3b256 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\211\347\253\240\357\274\232\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\350\277\220\350\241\214\346\240\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\270\211\347\253\240\357\274\232\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\350\277\220\350\241\214\346\240\210.md"
@@ -2,9 +2,9 @@
## 复习
-- 函数把一段工作打包并命名
-- 调用函数=传参、跳入、执行、返回
-- 返回地址怎么记、局部数据放哪里,还留着没解决
+- 变量、类型与表达式:名字如何代表数据,表达式如何变成运算
+- 分支与循环:高级语言结构如何落到比较和跳转指令
+- 函数:把一段工作命名、传入参数并获得结果
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十二章:函数.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\345\207\275\346\225\260.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\345\207\275\346\225\260.md"
index 33ba2857..89abe876 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\345\207\275\346\225\260.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\214\347\253\240\357\274\232\345\207\275\346\225\260.md"
@@ -2,9 +2,9 @@
## 复习
-- 判断由比较和条件跳转实现
-- 循环是“往回跳”加一个结束判断
-- 程序目前仍是一条从头写到尾的长条
+- 高级语言:再加一层:从“控制机器”转向“描述问题”
+- 变量、类型与表达式:名字如何代表数据,表达式如何变成运算
+- 分支与循环:高级语言结构如何落到比较和跳转指令
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十五章:从源代码到可执行文件.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\224\347\253\240\357\274\232\344\273\216\346\272\220\344\273\243\347\240\201\345\210\260\345\217\257\346\211\247\350\241\214\346\226\207\344\273\266.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\224\347\253\240\357\274\232\344\273\216\346\272\220\344\273\243\347\240\201\345\210\260\345\217\257\346\211\247\350\241\214\346\226\207\344\273\266.md"
index a9db7e9f..1367dabd 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\224\347\253\240\357\274\232\344\273\216\346\272\220\344\273\243\347\240\201\345\210\260\345\217\257\346\211\247\350\241\214\346\226\207\344\273\266.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\344\272\224\347\253\240\357\274\232\344\273\216\346\272\220\344\273\243\347\240\201\345\210\260\345\217\257\346\211\247\350\241\214\346\226\207\344\273\266.md"
@@ -2,9 +2,9 @@
## 复习
-- 高级语言描述问题,汇编贴近机器,机器码是机器唯一认得的
-- 程序在内存里分为代码区、数据区、堆和栈
-- 但我们还没说清:写下的源码,怎样变成可运行的程序
+- 函数:把一段工作命名、传入参数并获得结果
+- 函数调用与运行栈:保存参数、局部变量和返回地址
+- 程序在内存里的样子:代码区、数据区、栈和堆的初步全景
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十六章:编译与解释.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\205\255\347\253\240\357\274\232\347\274\226\350\257\221\344\270\216\350\247\243\351\207\212.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\205\255\347\253\240\357\274\232\347\274\226\350\257\221\344\270\216\350\247\243\351\207\212.md"
index aa512f8a..ff280d06 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\205\255\347\253\240\357\274\232\347\274\226\350\257\221\344\270\216\350\247\243\351\207\212.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\205\255\347\253\240\357\274\232\347\274\226\350\257\221\344\270\216\350\247\243\351\207\212.md"
@@ -2,9 +2,9 @@
## 复习
-- 从源代码到可执行文件要经过编译、汇编、链接、加载
-- 编译器把高级语言翻译成汇编,内部暂时当作黑箱
-- 翻译完成之后,机器才能运行
+- 函数调用与运行栈:保存参数、局部变量和返回地址
+- 程序在内存里的样子:代码区、数据区、栈和堆的初步全景
+- 从源代码到可执行文件:编译、汇编和链接的完整流水线
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十四章:程序在内存里的样子.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\345\234\250\345\206\205\345\255\230\351\207\214\347\232\204\346\240\267\345\255\220.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\345\234\250\345\206\205\345\255\230\351\207\214\347\232\204\346\240\267\345\255\220.md"
index 9a436490..82ede52d 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\345\234\250\345\206\205\345\255\230\351\207\214\347\232\204\346\240\267\345\255\220.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\345\233\233\347\253\240\357\274\232\347\250\213\345\272\217\345\234\250\345\206\205\345\255\230\351\207\214\347\232\204\346\240\267\345\255\220.md"
@@ -2,9 +2,9 @@
## 复习
-- 函数调用靠栈保存返回地址和局部数据
-- 栈是后进先出,SP 指向栈顶
-- 递归就是同一函数的多层调用
+- 分支与循环:高级语言结构如何落到比较和跳转指令
+- 函数:把一段工作命名、传入参数并获得结果
+- 函数调用与运行栈:保存参数、局部变量和返回地址
## TL;DR
src/学习与进步/计算机科学极简入门指南/程序与编程基础/第四十章:变量、类型与表达式.md
+3 / -3 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\347\253\240\357\274\232\345\217\230\351\207\217\343\200\201\347\261\273\345\236\213\344\270\216\350\241\250\350\276\276\345\274\217.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\347\253\240\357\274\232\345\217\230\351\207\217\343\200\201\347\261\273\345\236\213\344\270\216\350\241\250\350\276\276\345\274\217.md"
index 051514f8..992de3fb 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\347\253\240\357\274\232\345\217\230\351\207\217\343\200\201\347\261\273\345\236\213\344\270\216\350\241\250\350\276\276\345\274\217.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\347\250\213\345\272\217\344\270\216\347\274\226\347\250\213\345\237\272\347\241\200/\347\254\254\345\233\233\345\215\201\347\253\240\357\274\232\345\217\230\351\207\217\343\200\201\347\261\273\345\236\213\344\270\216\350\241\250\350\276\276\345\274\217.md"
@@ -2,9 +2,9 @@
## 复习
-- 高级语言负责描述问题,不负责安排机器细节
-- 变量、表达式、控制结构、函数是它的几样基本工具
-- 这些工具最终都要落到寄存器、存储器和指令上
+- 名字、标签与地址:用名字和标签引用数据与跳转目标,不再手工数地址
+- 汇编器:通过两遍扫描,把符号汇编成机器码
+- 高级语言:再加一层:从“控制机器”转向“描述问题”
## TL;DR
更新记录(2026-09-17 11:49:25 +0000 | 81e4d856)
Summary
- Generated at:
2026-09-17 11:49:25 +0000 - Base commit:
81e4d856 - Diff source:
f6423e02363d9cf1e015cdbc71aa81603738e9d4..81e4d856e3ceddbe981e2fcbab03e1598647402d - Changed files:
15 - Total lines:
+1112 / -196
Index
- src/学习与进步/计算机科学极简入门指南/操作系统/第五十一章:内核态与用户态.md
+79 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十七章:调度要解决什么.md
+71 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十三章:程序如何变成进程.md
+65 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十九章:时间片与优先级调度.md
+70 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十二章:系统调用.md
+74 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十五章:进程控制块与进程状态.md
+86 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十八章:先来先服务与最短任务优先.md
+75 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十六章:上下文切换.md
+81 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十四章:进程的创建与结束.md
+77 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第五十章:操作系统是什么.md
+78 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十一章:多核调度(进阶).md
+73 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十二章:线程与并发.md
+68 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第六十章:多级反馈队列(进阶).md
+68 / -13 - src/学习与进步/计算机科学极简入门指南/操作系统/第四十九章:引导程序与内核加载.md
+74 / -14 - src/学习与进步/计算机科学极简入门指南/操作系统/第四十八章:按下电源:复位与固件.md
+73 / -13
Diffs
src/学习与进步/计算机科学极简入门指南/操作系统/第五十一章:内核态与用户态.md
+79 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
index 9b1a59bb..fc10bd68 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\200\347\253\240\357\274\232\345\206\205\346\240\270\346\200\201\344\270\216\347\224\250\346\210\267\346\200\201.md"
@@ -1,35 +1,101 @@
-# 第五十一章:内核态与用户态
+# 内核态与用户态
## 复习
-- 操作系统需要管理所有程序共享的硬件资源。
+- 操作系统是资源的管理者和抽象的提供者
+- 内核常驻内存,程序通过它请求服务
+- 内核权力很大,不能任由普通程序指挥
## TL;DR
-- CPU 用不同特权级区分内核代码与普通程序。
-- 用户态程序不能直接执行危险指令或任意访问硬件。
+- CPU 有两种运行模式:**内核态** 和 **用户态**
+- 危险操作只在核态可执行,用户程序只能做受限的事
+- 用户程序要请求内核服务,必须经过受控入口切换到核态
+- 这条界线由硬件保证,是整套保护体系的地基
## 正文
- 若任意程序都能关闭中断、改写页表或直接控制磁盘,它一次错误就可能伤及整个系统。仅靠“程序员请小心”不够,保护必须由 CPU 执行。于是处理器提供至少两种运行状态:**内核态**拥有较高权限,**用户态**只能执行受限指令。
+ 上一章说,内核负责管理一切。既然它权力这么大,那普通程序能不能直接对它发号施令,甚至自己动手改内存、关中断、直接操作硬盘?
- 普通应用在用户态运行。它尝试进行特权操作时,CPU 会阻止它,并转入内核预设的处理流程。操作系统因此可以规定谁能访问设备、谁能改动内存映射。
+ 如果真能这样,一个写错的程序就足以让整台机器崩溃,一个恶意程序也能偷看别人的数据。系统必须有一道界线。
- 隔离不是为了为难程序,而是让不相干的程序可以放心共处。可应用仍需打开文件、申请内存。它怎样在不越界的前提下请内核代劳?
+### 两种模式
-**思考题**
+ 现代 CPU 提供至少两种运行模式,也叫**特权级**:
-> 为什么让应用自己检查“我是否有权限”不足以形成保护?
+- **内核态**(kernel mode):权限最高,可以执行所有指令、访问全部内存
+- **用户态**(user mode):权限受限,只能执行普通指令、访问属于自己的内存
+
+ 平时我们写的程序,都跑在用户态。
+
+### 特权指令
+
+ 那些“会动到全局”的指令,被划为**特权指令**,只在核态可以执行。比如:
+
+- 修改内存映射(谁能访问哪块内存)
+- 开关中断
+- 直接读写设备
+- 让 CPU 停机
+
+ 用户程序想干这些事,CPU 会直接拒绝。注意:这道界线不是靠“程序自觉”守住的,而是由 **CPU 硬件**强行把关——程序根本没法绕过。
+
+### 怎么跨过界线
+
+ 那用户程序要用磁盘、要发网络包,怎么办?总不能永远是用户态。
+
+ 答案是:**通过受控入口,从用户态陷入内核态。** 常见的入口有三类:
+
+- **系统调用**:用户程序主动请求内核帮忙(下一章细讲)
+- **异常**:程序自己出了状况,比如除零、访问越界,CPU 转入内核处理
+- **中断**:外部设备发来信号,强制 CPU 先处理
+
+ 关键在于:用户程序**不能自己**切到核态,只能“触发一个入口”,由内核决定要不要、以及怎样处理。就像你能走进银行大厅,但要进金库,必须由柜台审核、放行。
+
+### 一次切换的样子
+
+```text
+用户态:程序正常运行
+ │ 触发系统调用 / 异常 / 中断
+ ▼
+内核态:内核接管,处理事件
+ │ 处理完毕
+ ▼
+用户态:程序继续运行
+```
+
+ 这种“用户态→内核态→用户态”的往返,是操作系统里最频繁的动作之一。它带来安全,也带来开销——毕竟换一次“身份”不免费。
+
+ 那么,“用户程序主动请求内核帮忙”这件事,到底是怎样正式表达的?这就要说到**系统调用**。
+
+ **思考题**
+
+> 假设没有内核态和用户态之分,任何程序都能直接操作硬件。一个普通的文本编辑器,可能会无意中造成哪些严重后果?这条界线保护的是“系统”,还是“程序”?
## 小结
-- 内核态可执行特权操作,用户态受到限制。
-- 权限检查依赖 CPU 强制执行,不能只依赖应用自觉。
+### 知识点
+
+- CPU 有两种模式:内核态与用户态
+- 特权指令只在核态可执行
+- 界线由硬件保证,程序无法绕过
+- 用户程序通过系统调用、异常、中断进入内核态
+
+### 参考资料
+
+1. [Wikipedia(zh):核心态](https://zh.wikipedia.org/wiki/%E6%A0%B8%E5%BF%83%E6%80%81):内核态与用户态
+2. [Wikipedia(zh):特权指令](https://zh.wikipedia.org/wiki/%E7%89%B9%E6%9D%83%E6%8C%87%E4%BB%A4):只允许内核执行的指令
+3. [Wikipedia(zh):保护环](https://zh.wikipedia.org/wiki/%E4%BF%9D%E6%8A%A4%E7%8E%AF):CPU 的特权级
### 思考题答案(仅供参考)
- 有问题或恶意的应用可以跳过自己的检查;只有硬件拒绝越权指令,规则才无法被它单方面取消。
+ 没有这条界线,一个普通文本编辑器就可能因为一个指针写错,覆盖掉别的程序甚至内核的数据,让整台机器崩溃;恶意程序更能直接读取别人的密码、篡改系统。这条界线表面上是限制程序,实际上是在保护每一个程序:正因为别人不能随便动你的内存、动系统,你自己的程序才有稳定运行的环境。它保护的是整个系统,也就是系统中的每一个程序。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十七章:调度要解决什么.md
+71 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
index 6d9e45bf..34693908 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\203\347\253\240\357\274\232\350\260\203\345\272\246\350\246\201\350\247\243\345\206\263\344\273\200\344\271\210.md"
@@ -1,35 +1,93 @@
-# 第五十七章:调度要解决什么
+# 调度要解决什么
## 复习
-- 上下文切换使一个 CPU 能在多个就绪进程之间轮换。
+- 上下文切换让 CPU 能在多个进程间来回
+- 进程有运行、就绪、阻塞三种状态
+- 就绪队列里排着许多“只差 CPU”的进程
## TL;DR
-- 调度是在相互冲突的目标间分配 CPU。
-- 常见目标包括响应快、完成多、公平和照顾重要任务。
+- 调度要回答两个问题:下一个让谁跑?让它跑多久?
+- 调度的目标彼此矛盾:响应快、吞吐高、够公平、分轻重
+- 这些目标无法同时满足,只能权衡
+- 没有“完美调度”,只有“适合某种场景的调度”
## 正文
- 让一个长任务独占 CPU,整体切换最少,却会让点击后毫无反应的交互程序显得很慢。频繁轮换能改善响应,却增加切换开销。优先照顾重要任务有用,却可能让低优先级任务长期等不到机会。
+ 就绪队列里排着一队进程,CPU 只有一个。该把 CPU 交给谁、交给它多久?这就是**调度**(scheduling)要解决的事。
- 因此没有脱离场景的“最佳调度”。批处理关注吞吐量和周转时间;桌面系统关注响应时间;实时系统还要满足截止期限。评价规则先于具体算法。
+ 听起来不过是从队伍里挑一个,可真正做起来,麻烦得很——因为我们想要的太多。
- 从最朴素的排队方法出发,我们可以看见这些取舍如何出现。
+### 两个基本问题
-**思考题**
+ 任何调度策略,都绕不开两件事:
-> 为什么提高某个进程的响应速度,可能降低总体吞吐量?
+1. **选谁**:下一个运行哪个进程
+2. **跑多久**:给它多长时间,之后要不要收回来
+
+ 不同的回答方式,就构成了不同的调度算法。
+
+### 四个互相打架的目标
+
+ 我们希望调度做到下面这些事:
+
+- **响应快**:你点了按钮,界面立刻有反应
+- **吞吐高**:单位时间里,尽量多完成一些任务
+- **够公平**:每个进程都该有机会,不能有人一直排不上
+- **分轻重**:重要的任务(比如系统关键进程)应该优先
+
+ 问题是,这四个目标经常互相拆台:
+
+- 想让后台大任务“吞吐高”,它最好一口气跑完;可这样一来,前台小任务就得干等,“响应快”没了
+- 想“够公平”,大家轮流跑;可“分轻重”又要求某些进程多占一些
+
+ 想要面面俱到,往往哪一面都做不好。**调度的本质,是在这些目标之间做取舍。**
+
+### 怎么衡量好坏
+
+ 既然要取舍,就得有一套量尺。常用的有:
+
+- **周转时间**:从提交到完成一共花了多久
+- **等待时间**:在就绪队列里一共等了多久
+- **响应时间**:从提交到第一次有反应,隔了多久
+
+ 不同的场景,看重的指标不同:批处理更在意吞吐和周转,交互系统更在意响应。
+
+### 没有万能解
+
+ 正因为目标互相冲突,调度领域里没有“一统天下”的算法。有的算法简单、公平,但一趟长任务就能把大家堵住;有的算法平均表现最好,却可能饿死个别进程。
+
+ 理解了这些矛盾,再看后面几种具体算法,就会明白它们各自在“牺牲什么、换来什么”。先从最简单的两种说起。
+
+ **思考题**
+
+> “响应快”和“吞吐高”为什么经常打架?举一个你日常用电脑时能感受到的例子。
## 小结
-- 调度目标之间常有取舍。
-- 工作负载决定什么指标更重要。
+### 知识点
+
+- 调度回答“选谁”和“跑多久”
+- 调度的目标:响应、吞吐、公平、优先级
+- 这些目标彼此冲突,需要权衡
+- 衡量指标:周转时间、等待时间、响应时间
+
+### 参考资料
+
+1. [Wikipedia(zh):调度](https://zh.wikipedia.org/wiki/%E8%B0%83%E5%BA%A6_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)):调度的基本问题
+2. [Wikipedia(zh):排程](https://zh.wikipedia.org/wiki/%E6%8E%92%E7%A8%8B):进程调度概述
### 思考题答案(仅供参考)
- 为它频繁切换或抢占 CPU 会占用管理时间,并延后其他连续工作完成的机会。
+ 想让“吞吐高”,就希望一个任务尽量一气呵成地跑完,减少切换和等待;可这会让别的任务长时间得不到 CPU,交互操作就得干等,“响应”变差。反过来,为了“响应快”而频繁切换,又会让每次切换的开销累积起来,吞吐下降。例如一边下载大文件、一边敲字:下载希望占满带宽和磁盘,输入法却希望每个按键都被立刻响应。两者抢的就是同一份资源,天然的矛盾。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十三章:程序如何变成进程.md
+65 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
index 2ac0e319..cc48ca69 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\270\211\347\253\240\357\274\232\347\250\213\345\272\217\345\246\202\344\275\225\345\217\230\346\210\220\350\277\233\347\250\213.md"
@@ -1,35 +1,87 @@
-# 第五十三章:程序如何变成进程
+# 程序如何变成进程
## 复习
-- 系统调用让应用安全请求内核服务。
+- 操作系统是资源的管理者和抽象提供者
+- 用户程序通过系统调用请求内核服务
+- 内核要管理的,是一个又一个“正在运行的程序”
## TL;DR
-- 程序是静态文件,进程是一次正在进行的执行活动。
-- 每个进程拥有执行现场、地址空间和内核记录。
+- **程序**是磁盘上的静态文件;**进程**是正在运行的程序
+- 同一份程序可以被加载很多次,变成多个互不相同的进程
+- 进程 = 程序 + 运行状态 + 占用的资源
+- 内核负责把一个静态程序“变成”一个活生生的进程
## 正文
- 磁盘里的编辑器只是一些字节;双击它、甚至同时打开两份它以后,才有一个或多个**进程**。进程包含机器指令正在执行到哪里、寄存器当前是什么、哪些内存属于它、打开了哪些文件等运行现场。
+ 你双击一个程序,它就跑起来了。可仔细想想:磁盘上的那个文件,从头到尾一个字都没变,它怎么就“跑起来”了?
- 同一份程序文件可以产生多个彼此独立的进程。它们的代码或许相同,输入、变量、栈和执行位置却各不相同。因此操作系统管理的单位不是“文件名”,而是每个运行中的进程。
+ 这里要区分两个概念。
- 进程怎样出生、换成另一份程序,结束后又怎样回收?这些生命期动作正是下一章的主题。
+### 静态与动态
-**思考题**
+- **程序**(program):躺在磁盘上的可执行文件,是一堆静态的指令和数据。它不会自己动。
+- **进程**(process):程序被装进内存、正在执行的那一份,是动态的、活着的。
-> 同时打开两个同一款文字编辑器,为什么通常是两个进程?
+ 好比菜谱和做菜:菜谱印在纸上,永远是那几行字;照着菜谱下厨,才会有切菜、翻炒、出锅这些正在发生的事。菜谱是程序,那个正在进行的“做菜过程”是进程。
+
+ 同一个程序可以同时对应多个进程。比如你打开两个文本编辑器,用的是一模一样的可执行文件,却是两个独立进程——各自的文档、光标位置、改动,互不干扰。
+
+### 内核要记住什么
+
+ 一旦程序开始运行,内核就得把它“管起来”。为此,它要为这个进程记下不少东西:
+
+- 程序被放在内存的哪里
+- 现在执行到哪条指令(PC 是多少)
+- 各个寄存器里是什么值
+- 占用了哪些资源(内存、打开的文件、设备)
+- 现在是什么状态(正在跑,还是在等)
+
+ 这些信息加起来,才构成一个完整的“正在运行的程序”。而它们,都会记在一个专门的数据结构里——下一章会细讲。
+
+### 内核怎样“制造”一个进程
+
+ 把一个静态程序变成进程,内核大致要做这几件事:
+
+1. 把程序的代码和数据装入内存
+2. 为它建立起一片属于自己的地址空间
+3. 准备好运行所需的栈和初始寄存器
+4. 把 PC 指向程序的入口
+5. 把它标记为“就绪”,等着被调度上 CPU
+
+ 做完这些,程序就有了“生命”,成了一个进程。接下来,它就可以和别的进程一起,轮流使用 CPU。
+
+ 那么,一个进程又是从哪里来的?是凭空冒出来的,还是由别的进程“生”出来的?下一章,我们看进程的出生与死亡。
+
+ **思考题**
+
+> 同一份可执行文件,被运行了三次,产生了几个进程?它们之间会不会互相影响各自的变量和文件?为什么?
## 小结
-- 程序是静态内容,进程是运行中的实例。
-- 进程保存自己的现场和资源。
+### 知识点
+
+- 程序是静态文件,进程是正在运行的程序
+- 同一程序可以有多个进程
+- 进程 = 程序 + 运行状态 + 占用的资源
+- 内核把静态程序装入内存、建立地址空间、准备运行环境
+
+### 参考资料
+
+1. [Wikipedia(zh):进程](https://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B):进程的概念
+2. [Wikipedia(zh):程序](https://zh.wikipedia.org/wiki/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F):程序与进程的区别
### 思考题答案(仅供参考)
- 两扇窗口需要各自的文档、变量和执行状态;它们虽来自同一程序文件,也必须作为独立运行实体管理。
+ 产生三个进程。它们虽然来自同一个文件,却各自拥有独立的运行状态和资源:各自的内存空间、各自的变量、各自的寄存器值。一个进程改动自己的变量或文件,不会直接改变另外两个。也正因如此,同一程序才能被安全地同时运行多份。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十九章:时间片与优先级调度.md
+70 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
index 00f79b5d..9f2db3a5 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\271\235\347\253\240\357\274\232\346\227\266\351\227\264\347\211\207\344\270\216\344\274\230\345\205\210\347\272\247\350\260\203\345\272\246.md"
@@ -1,35 +1,92 @@
-# 第五十九章:时间片与优先级调度
+# 时间片与优先级调度
## 复习
-- 不抢占的简单调度会让短而急的任务久等。
+- FCFS 简单,但长任务会堵住后面的人
+- SJF 平均等待最短,却不知道运行时间、还会饿死长任务
+- 现实需要兼顾“响应快”和“分轻重”
## TL;DR
-- 时间片让进程最多运行一小段时间就让出 CPU。
-- 优先级能表达任务重要性,但需防止低优先级饥饿。
+- 时间片轮转:每个进程只跑一小段,时间一到就换人,保证人人有份
+- 时间片太小,切换开销大;太大,又退化成先来先服务
+- 优先级调度:重要的先跑,但低优先级可能被饿死
+- 老化:等得越久,临时提高优先级,防止长期挨饿
## 正文
- **时间片轮转**把 CPU 时间切成小段。时间片到达时,内核可抢占当前进程,换下一个就绪进程;每个交互程序因而很快再次获得机会。片太长接近先来先服务,太短又会被切换成本吞掉。
+ 先来先服务和最短任务优先,一个太“死板”,一个太“理想”。现实中的系统,既想让交互程序快速响应,又想让重要任务优先完成。于是有了两种更实用的思路:切小片轮着跑,以及按重要性排座次。
- 系统也可按**优先级**选择就绪进程,例如优先回应正在与人交互的程序。为避免低优先级永远等待,常会随等待时间逐步提高其优先级,这叫老化。
+### 时间片轮转
- 如果任务长短未知,能否从它实际表现中学习优先级?
+ **时间片轮转**(RR,Round Robin)的做法是:给每个进程一小段时间,叫一个**时间片**(time slice),让它跑;时间一到,无论跑没跑完,都强制换下一个,自己回到就绪队列的队尾。
-**思考题**
+```text
+A 跑一个片 │ B 跑一个片 │ C 跑一个片 │ A 再跑一个片 │ ……
+```
-> 时间片为什么不能无限缩短?
+ 这样,每个进程最多等“队伍长度 × 时间片”的时间,就能轮到自己。交互程序要的“响应快”,靠它来保证。
+
+ 时间片的大小很有讲究:
+
+- 太**小**:进程还没干多少活就被换下,切换开销占比变大,吞吐下降
+- 太**大**:一个进程又要等很久才轮到,退化成先来先服务,响应变差
+
+ 所以时间片要取一个折中值——通常远大于一次上下文切换的开销,又不至于让人明显感到卡顿。
+
+### 优先级调度
+
+ 可有些进程就是更“要紧”:负责接收用户输入的、负责网络通信的、系统的关键进程……时间片轮转一视同仁,对它们不够友好。
+
+ 于是有了**优先级调度**:给每个进程一个优先级,**优先级高的先上 CPU**。同优先级之间,可以再用时间片轮转。
+
+ 优先级有两种来路:
+
+- 静态:一开始定好,运行中不变
+- 动态:根据情况调整,比如刚用完 CPU 的降一点、刚等待完 I/O 的升一点
+
+### 饥饿与老化
+
+ 优先级调度有个老毛病:**低优先级的进程可能一直排不上队**。只要高优先级的任务源源不断,低优先级的就会一直等下去,这叫**饥饿**(starvation)。
+
+ 解决办法叫**老化**(aging):进程等待的时间越长,就慢慢把它的优先级抬一点。等得够久,再低的优先级也能熬出头,最终被调度一次。这样一来,“分轻重”和“够公平”之间就有了一条折中的路。
+
+### 现实里的组合
+
+ 真实的调度器,很少只用一种办法,而是把上面几招组合起来:**优先级决定大致座次,时间片保证人人轮得到,老化兜住被冷落的进程。** 调度的艺术,就在于把这些互相拉扯的目标,调到一个多数场景都满意的平衡点。
+
+ 到这里,调度的基本招式就讲完了。可有心的读者会问:如果系统里有成千上万个进程,一个个比较优先级是不是太慢?还有一个更聪明的“反馈”办法。下一章,我们看**多级反馈队列**——它连“任务大概要跑多久”都不用事先知道。
+
+ **思考题**
+
+> 时间片设成多大才合适?如果系统主要跑的是交互程序,你会倾向选大还是选小?如果主要跑的是批量计算任务呢?
## 小结
-- 抢占式时间片改善交互响应。
-- 优先级调度常需老化机制维持公平。
+### 知识点
+
+- 时间片轮转:轮流跑一小段,保证响应
+- 时间片大小的权衡
+- 优先级调度:重要的先跑
+- 饥饿与老化
+- 现实调度常把优先级、时间片、老化组合使用
+
+### 参考资料
+
+1. [Wikipedia(zh):时间片](https://zh.wikipedia.org/wiki/%E6%97%B6%E9%97%B4%E7%89%87):时间片轮转
+2. [Wikipedia(zh):优先级调度](https://zh.wikipedia.org/wiki/%E4%BC%98%E5%85%88%E7%BA%A7%E8%B0%83%E5%BA%A6):优先级与老化
+3. [Wikipedia(zh):饥饿 (计算机科学)](https://zh.wikipedia.org/wiki/%E9%A5%A5%E9%A5%BF_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)):进程饥饿
### 思考题答案(仅供参考)
- 每次切换都要保存和恢复现场;片过短时,大量时间消耗在切换而非完成工作上。
+ 时间片要足够大,能盖过一次上下文切换的开销,又不至于让等待的人明显感到卡顿。若主要跑交互程序,倾向选小一些:宁可多切换几次,也要让每次点击、按键都尽快有反应。若主要跑批量计算任务,倾向选大一些:这类程序对响应不敏感,少切换反而更省,吞吐更高。所以没有固定答案,要看系统主要面对什么样的负载。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十二章:系统调用.md
+74 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
index 8e455f82..ede297ff 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\214\347\253\240\357\274\232\347\263\273\347\273\237\350\260\203\347\224\250.md"
@@ -1,35 +1,96 @@
-# 第五十二章:系统调用
+# 系统调用
## 复习
-- 用户态程序不能直接操作关键硬件和全局资源。
+- CPU 分为内核态与用户态,界线由硬件保证
+- 用户程序要进入内核,必须经过受控入口
+- 系统调用就是其中的一类入口
## TL;DR
-- 系统调用是应用请求内核服务的受控入口。
-- CPU 在调用时切换到内核态,内核检查请求后再返回用户态。
+- 系统调用是用户程序请求内核服务的正式接口
+- 它触发一次从用户态到内核态的切换,由内核代为完成
+- 内核按“编号”分发,做完再把结果返回用户程序
+- 它看起来像函数调用,但开销要大得多
## 正文
- 应用想读文件时,不该自己驱动磁盘;它会发出 `read` 一类**系统调用**。这不是普通函数调用:程序把请求编号和参数放在规定位置,执行一条特殊指令;CPU 保存现场并切换到内核态,跳入内核的调用处理程序。
+ 程序想读一个文件、申请一块内存、往网络发一个包,这些事它自己都做不了——权限不够。它只能求内核帮忙。这个“求”的正式方式,就是**系统调用**(system call)。
- 内核先确认参数是否合法、文件是否允许访问,再完成实际工作,把结果交回应用并恢复用户态。这样,方便的“读文件”留在应用手中,危险的设备操作仍被内核集中控制。
+### 一次系统调用长什么样
- 系统调用是操作系统向应用露出的门。走进这扇门前,先要分清桌面上的程序文件和正在运行的那份实体。
+ 用户程序想请内核办事,大致按这个流程:
-**思考题**
+1. 把“要办哪件事”的**编号**,和需要的**参数**,放到约定的位置(通常是几个寄存器)
+2. 执行一条特殊的“陷入”指令,主动从用户态进入内核态
+3. 内核根据编号,在表里查到对应的处理程序
+4. 内核完成工作,把结果放回约定位置,返回用户态
-> 系统调用为什么不能只是用户态中的普通库函数?
+ 这很像去银行办事:先填一张单子(参数),取一个号(编号),柜员按号办理,办完把回执给你。你进不了金库,但通过柜台,事情照样办成了。
+
+```text
+用户程序:放编号和参数 → 陷入 →(内核态)内核处理 → 返回
+```
+
+### 它像函数调用,但不一样
+
+ 从写法上看,系统调用和普通函数调用差不多:都是“把参数传进去,拿个结果回来”。可两者有本质区别:
+
+- 普通函数调用,仍在用户态内执行,跳进跳出的只是代码
+- 系统调用会**切换特权级**,进入内核态再回来
+
+ 特权级切换不便宜:要保存现场、切换栈、做权限检查。所以能少调就少调——这也是为什么读文件常常一次读一大块,而不是一个字节一个字节地调。
+
+### 常见的系统调用
+
+ 系统调用名目很多,但常用的也就那几类:
+
+- 文件:打开、读、写、关闭
+- 进程:创建、结束、等待
+- 内存:申请、释放
+- 通信:网络收发、管道读写
+
+ 它们可以说是“操作系统功能的正式出口”。程序想用操作系统的任何能力,基本都要经过它们。
+
+### 库函数与系统调用
+
+ 你可能会有个疑问:平时写代码,好像从没“手动陷入内核”过,只是调了个函数就完事了。
+
+ 这是因为**库函数**替你包了一层。比如打印用的 `printf`,它自己并不直接操作硬件;它把内容整理好,最终去调用内核的“写”系统调用,由内核把数据送到屏幕或文件。类似地,很多库函数只是“包装”,真正陷入内核的是它内部那一次系统调用。
+
+ 一层套一层,人写起来简单,底层却老老实实地走了正规流程——这正是我们一路见到的加层思路。
+
+ 到这里,“程序如何请求内核”就清楚了。可内核要管理的是一个又一个**正在运行的程序**。它怎样把一个静静躺在磁盘上的程序,变成一个正在占用 CPU 的“活物”?下一章,我们认识一个关键概念:**进程**。
+
+ **思考题**
+
+> 既然系统调用和普通函数调用长得差不多,为什么不让用户程序直接执行内核代码,省掉切换?这样会带来什么问题?
## 小结
-- 系统调用在用户态与内核态之间建立受控通道。
-- 内核负责验证请求并操作受保护资源。
+### 知识点
+
+- 系统调用是用户程序请求内核服务的接口
+- 一次系统调用:放编号与参数、陷入内核、内核处理、返回
+- 系统调用会切换特权级,开销比普通函数大
+- 库函数常常封装了系统调用
+
+### 参考资料
+
+1. [Wikipedia(zh):系统调用](https://zh.wikipedia.org/wiki/%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8):系统调用的机制
+2. [Wikipedia(zh):POSIX](https://zh.wikipedia.org/wiki/POSIX):常见的系统调用接口标准
+3. [Wikipedia(zh):C 标准库](https://zh.wikipedia.org/wiki/C%E6%A0%87%E5%87%86%E5%BA%93):库函数与系统调用的关系
### 思考题答案(仅供参考)
- 普通函数没有改变 CPU 特权级的能力,不能安全地执行只有内核态允许的操作。
+ 如果让用户程序直接执行内核代码,就等于取消了那两种模式:任何程序都能以最高权限为所欲为,改内存、动设备、绕过保护,系统立刻失去安全和稳定。系统调用虽然多了一次切换的开销,却换来两道保险:入口是固定的、可控的,内核可以在“放行”之前检查参数是否合法。用一点性能换取安全与秩序,非常划算。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十五章:进程控制块与进程状态.md
+86 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
index d04551e4..26893908 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\344\272\224\347\253\240\357\274\232\350\277\233\347\250\213\346\216\247\345\210\266\345\235\227\344\270\216\350\277\233\347\250\213\347\212\266\346\200\201.md"
@@ -1,35 +1,108 @@
-# 第五十五章:进程控制块与进程状态
+# 进程控制块与进程状态
## 复习
-- 内核负责创建、装入、结束和回收进程。
+- 进程由已有进程创建,形成一棵进程树
+- 进程结束时留下退出状态,等待父进程回收
+- 内核要管理许多进程,必须清楚记得每一个
## TL;DR
-- 进程控制块保存内核管理一个进程所需的记录。
-- 运行、就绪和阻塞说明进程分别在用 CPU、等 CPU 或等事件。
+- 内核用**进程控制块(PCB)** 记录一个进程的全部信息
+- PCB 里有身份、运行现场、占用资源和当前状态
+- 进程有三种基本状态:运行、就绪、阻塞
+- 状态随事件彼此转换,内核据此决定让谁上 CPU
## 正文
- 内核不能把进程的所有信息记在“脑中”。它为每个进程保存一份**进程控制块**(PCB):其中有进程编号、寄存器现场、状态、调度信息、内存映射和打开资源的索引等。
+ 内核同时管着成百上千个进程。它总得有个地方,把每个进程的情况记下来。这个“档案”,就是**进程控制块**(PCB,Process Control Block)。
- 一个进程可能是**运行**的,表示它此刻占用 CPU;也可能是**就绪**的,表示万事具备只等 CPU;还可能是**阻塞**的,例如正在等待键盘输入或磁盘完成。阻塞不是“没有工作”,而是继续运行也不会取得进展,应该先让出 CPU。
+### 一份进程档案
- 状态和 PCB 让内核可以从一堆进程中挑选下一个。真正换人时,要如何保存一个现场、恢复另一个现场?
+ PCB 是内核为每个进程维护的数据结构。前面几章零零散散提到的信息,最后都收在这里:
-**思考题**
+- **身份**:进程编号,父子是谁
+- **运行现场**:PC 值、各寄存器的内容、栈的位置
+- **资源**:占用了哪些内存、打开了哪些文件
+- **状态**:它是正在跑,还是闲着,还是在等
+- **调度信息**:优先级等,供内核决定谁先上 CPU
-> 等待磁盘读取的进程为什么不应一直处于运行状态?
+ 可以说,PCB 就是进程在操作系统里的“户口本”。找到 PCB,就等于找到了这个进程的一切。
+
+### 三种基本状态
+
+ 一个进程,随时处在下列三种基本状态之一:
+
+- **运行(Running)**:正占用 CPU,在跑
+- **就绪(Ready)**:一切都准备好了,只差一个 CPU
+- **阻塞(Blocking)**:在等某个事件发生,就算给它 CPU 也没用
+
+ “就绪”和“阻塞”最容易混。区别在于:
+
+- 就绪,是**缺 CPU**
+- 阻塞,是**缺事件**(比如等磁盘读完、等用户按键)
+
+### 状态怎么变
+
+ 状态不是固定的,它会随事件来回转换:
+
+```text
+ ┌──────────── 被调度 ────────────┐
+ ▼ │
+ ┌───────┐ 时间片用完 ┌───────┐ │
+ │ 就绪 │ ───────────────>│ 运行 │───┘
+ └───────┘ <───────────────└───────┘
+ ▲ 事件完成 │ 等待事件
+ │ ▼
+ │ ┌───────┐
+ └───────────────────│ 阻塞 │
+ └───────┘
+```
+
+- 就绪 → 运行:内核选中了它,把 CPU 交给它
+- 运行 → 就绪:时间片用完(不能让一个进程一直霸着 CPU)
+- 运行 → 阻塞:它要等一件事,比如发起了一次磁盘读取
+- 阻塞 → 就绪:它等的事情完成了,重新排队等 CPU
+
+ 顺带一提:**阻塞的进程不会“占着 CPU 空等”**。它一进入阻塞,内核就把 CPU 让给别的就绪进程,自己去等事件——这正是不让 CPU 浪费的关键。
+
+### 队列
+
+ 把同状态的进程排到一起,管理起来就方便了:所有就绪的进程排成**就绪队列**,谁被调度就看这个队列;等待不同事件的进程,分别排在各自的**阻塞队列**里。
+
+ 于是内核的调度工作,很大程度上就是:在就绪队列里挑一个,运行它;它一旦让出 CPU,再挑下一个。
+
+ 既然多个就绪进程要轮流上 CPU,那“换人”这件事就必须做利索。下一章,我们看内核怎样干净地把 CPU 从一个进程交给另一个——**上下文切换**。
+
+ **思考题**
+
+> 一个进程发起磁盘读取后进入阻塞,另一个进程还在就绪队列里等着。如果内核不把前者的状态从“运行”改成“阻塞”,会发生什么?为什么“就绪”和“阻塞”必须分开?
## 小结
-- PCB 是内核记录进程状态和资源的档案。
-- 运行、就绪、阻塞区分 CPU 与外部事件的等待关系。
+### 知识点
+
+- PCB 记录进程的身份、现场、资源与状态
+- 三种基本状态:运行、就绪、阻塞
+- 就绪缺 CPU,阻塞缺事件
+- 状态随调度与事件相互转换
+- 同状态的进程排成队列,便于管理
+
+### 参考资料
+
+1. [Wikipedia(zh):进程控制块](https://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%9D%97):PCB
+2. [Wikipedia(zh):进程状态](https://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B%E7%8A%B6%E6%80%81):运行、就绪与阻塞
### 思考题答案(仅供参考)
- 磁盘尚未给出数据时它无法继续计算;让它占着 CPU 只会浪费时间,其他就绪进程可以先运行。
+ 如果不把它改成阻塞,内核会以为它还能继续跑,于是反复把它调度上 CPU;可它实际在等磁盘,上 CPU 也只会再次发现“还没好”,白白浪费 CPU 时间。把“就绪”和“阻塞”分开,内核才能一眼看出:哪些进程给了 CPU 就能干活,哪些进程给了也是白给。这样才能把 CPU 只分给真正能用它的进程,避免空转。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十八章:先来先服务与最短任务优先.md
+75 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
index f2548718..06ebd9f8 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\253\347\253\240\357\274\232\345\205\210\346\235\245\345\205\210\346\234\215\345\212\241\344\270\216\346\234\200\347\237\255\344\273\273\345\212\241\344\274\230\345\205\210.md"
@@ -1,35 +1,97 @@
-# 第五十八章:先来先服务与最短任务优先
+# 先来先服务与最短任务优先
## 复习
-- 调度需要在响应、吞吐量和公平之间取舍。
+- 调度要决定“选谁”和“跑多久”
+- 目标之间彼此冲突:响应、吞吐、公平、优先级
+- 先看两种最朴素的选人办法
## TL;DR
-- 先来先服务简单公平,却会让短任务排在长任务后面。
-- 最短任务优先可缩短平均等待,却需要预知任务长度并可能造成饥饿。
+- 先来先服务(FCFS):按到达顺序排队,简单,但一个长任务会堵住所有人
+- 最短任务优先(SJF):先做预计最快的,平均等待时间最短
+- SJF 的难点:事先并不知道任务要跑多久,还可能饿死长任务
## 正文
- **先来先服务**按到达顺序运行。它很容易理解,却会产生“车队效应”:一个长计算任务排在最前,后面很多只需几毫秒的任务也得等它完成。
+ 调度的第一层问题,是“选谁”。最自然、最符合直觉的两种选法,是先来先服务和最短任务优先。
- **最短任务优先**改为先运行预计最短的任务,平均等待时间常会更小。但系统往往不知道一个程序还要跑多久;而且不断到来的短任务可能让长任务永远排不到,称为饥饿。
+### 先来先服务
- 交互系统通常不能等任务完成才换人,需要一种能主动轮流的方案。
+ **先来先服务**(FCFS,First Come First Served)就是排队买票:谁先到,谁先上;上了就一直跑,直到完成或主动让出。
-**思考题**
+ 它足够简单、足够公平——按到达顺序来,谁也挑不出毛病。但它有个要命的毛病:**一个长任务,会把后面所有人堵住。**
-> 最短任务优先为何不一定公平?
+ 举个例子。三个任务几乎同时到达,分别要跑 1、1、10 个单位时间。若按这个顺序:
+
+```text
+A(1) │ B(1) │ C(10)
+等待:A=0,B=1,C=2,平均等待 ≈ 1
+```
+
+ 没问题。可如果长任务 C 偏偏排在前面:
+
+```text
+C(10) │ A(1) │ B(1)
+等待:C=0,A=10,B=11,平均等待 = 7
+```
+
+ 两个一眨眼就能完的小任务,硬生生被压在后面等了很久。这种现象叫**护航效应**:一个“大块头”霸着 CPU,后面一队“小船”只能干等。
+
+### 最短任务优先
+
+ 既然长任务挡路是问题所在,那就反过来:**先做预计最快的**。这就是**最短任务优先**(SJF,Shortest Job First)。
+
+ 还是那三个任务,两个 1 和一个 10。不管谁先到,只要让两个短任务先跑,平均等待时间就是最小的:
+
+```text
+A(1) │ B(1) │ C(10)
+等待:A=0,B=1,C=2,平均等待 = 1
+```
+
+ 可以证明,在所有任务都同时到达的情况下,SJF 的平均等待时间是所有调度中最小的。这也是它最大的优点。
+
+### 可惜,两个现实问题
+
+ SJF 好,但有两个绕不过去的问题:
+
+- **怎么知道要跑多久?** 调度器手里只有一个准备运行的进程,它没法准确预知“这个进程还需要多少时间”。只能靠历史来猜,猜得准不准,全看运气。
+- **长任务会被饿死。** 只要短任务源源不断地来,长任务就一直排不上队——理论上的“平均最优”,换来的是个别进程的“永不执行”。这叫**饥饿**(starvation)。
+
+### 抢占还是不抢占
+
+ 上面的 SJF,默认是“一旦开始就跑完”,这叫**非抢占**。如果允许在更短的任务到来时打断当前任务,就叫**抢占式**。抢占能进一步降低平均等待,但代价是更多的上下文切换。
+
+ 这两种朴素算法,一个赢在简单,一个赢在平均表现,却都照顾不好“交互体验”。现实中的系统,还需要更灵活的办法——让每个进程都能在短时间内轮上一圈。下一章,我们看时间片和优先级。
+
+ **思考题**
+
+> FCFS 的“护航效应”,和你生活里哪些排队场景很像?如果只能知道每个任务“大概要多久”,你会怎么决定先服务谁?
## 小结
-- FCFS 容易出现长任务堵住短任务。
-- SJF 改善平均等待,却有预测和饥饿问题。
+### 知识点
+
+- FCFS:按到达顺序,简单但可能产生护航效应
+- SJF:最短的优先,平均等待时间最小
+- SJF 不知道运行时间,且可能饿死长任务
+- 抢占式与非抢占式的区别
+
+### 参考资料
+
+1. [Wikipedia(zh):先来先服务](https://zh.wikipedia.org/wiki/%E5%85%88%E6%9D%A5%E5%85%88%E6%9C%8D%E5%8A%A1):FCFS
+2. [Wikipedia(zh):最短作业优先](https://zh.wikipedia.org/wiki/%E6%9C%80%E7%9F%AD%E4%BD%9C%E4%B8%9A%E4%BC%98%E5%85%88):SJF
### 思考题答案(仅供参考)
- 若短任务持续到来,长任务会不断被排到后面,即使它早已等待很久。
+ 超市只开一个收银台、前面的人买了一大车东西,后面的队伍就全卡住了,这很像护航效应;高速收费站只有一个窗口、前面一辆大货车,也一样。如果知道每个任务“大概多久”,一个朴素而有效的办法是:让快的先过,长任务则排在有快任务之后,同时给长任务一个“等待补偿”——等得越久,越优先,避免它被一直插队饿死。这正是“优先级加老化”的思路。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十六章:上下文切换.md
+81 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
index e1b3114e..6fc7e04d 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\205\255\347\253\240\357\274\232\344\270\212\344\270\213\346\226\207\345\210\207\346\215\242.md"
@@ -1,35 +1,103 @@
-# 第五十六章:上下文切换
+# 上下文切换
## 复习
-- PCB 保存进程的状态和执行现场。
+- 内核用 PCB 记录每个进程的信息与状态
+- 进程分为运行、就绪、阻塞三种状态
+- 多个就绪进程要轮流使用同一个 CPU
## TL;DR
-- 上下文切换先保存当前进程现场,再恢复另一个进程现场。
-- 它让一个 CPU 看似同时服务多个进程,也有不可省去的成本。
+- **上下文**就是一个进程当前的运行现场:PC、寄存器、栈等
+- **上下文切换**:保存当前进程的现场,恢复下一个进程的现场
+- 切换由内核完成,是实现“同时运行多个程序”的关键
+- 切换本身不干“有用功”,还伴随额外开销,因此不宜过于频繁
## 正文
- 当时间片用完或当前进程阻塞,内核把它的程序计数器、寄存器等现场写入 PCB,再从另一个 PCB 取出保存的值,恢复相应的地址空间,最后返回用户态。这个动作叫**上下文切换**。
+ 就绪队列里排着好几个进程,可 CPU 只有一个。让谁上?跑一会儿之后,又该怎么换人?
- 被换出的进程并没有从头开始;下次恢复时,它会从原来停下的那条指令继续。切换本身不直接完成用户工作,还会影响缓存,所以调度不能为切换而切换。
+ 换人这件事的关键,在于**记住上一个人做到哪了**。
- 既然 CPU 时间有限,究竟应优先恢复哪个就绪进程?这就是调度问题。
+### 上下文是什么
-**思考题**
+ 一个进程正在运行时,它的全部“现场”都体现在 CPU 的状态里:
-> 为什么只保存程序计数器还不足以恢复一个进程?
+- PC 指向哪条指令
+- 各个寄存器里是什么值
+- 栈指针指向哪里
+- 它正在用哪片内存
+
+ 这些信息合起来,就叫进程的**上下文**(context)。只要把上下文原样恢复,进程就能像从没被打断过一样继续跑。
+
+### 切换的三步
+
+ 上下文切换(context switch)大致分三步:
+
+1. **保存**:把当前进程的 PC、寄存器等,存进它的 PCB
+2. **选择**:内核从就绪队列里挑出下一个要运行的进程
+3. **恢复**:从那个进程的 PCB 里,把它的现场装回 CPU
+
+ 做完这三步,CPU 上跑的就已经是另一个进程了。
+
+```text
+进程 A 运行
+ │ 保存 A 的上下文到 A 的 PCB
+ │ 从就绪队列选中 B
+ │ 从 B 的 PCB 恢复 B 的上下文
+ ▼
+进程 B 运行
+```
+
+ 好比两个人接力做同一道题:第一个人做一半要走,先把“算到哪一步、草稿写了什么”记下来;第二个人接手时,照着记下的内容接着算。题没变,只是换了个脑子。
+
+### 切换的开销
+
+ 上下文切换让“多个程序同时运行”成为可能,但它并不便宜:
+
+- 保存和恢复现场本身就要花时间,这段工夫不推进任何进程
+- 切换会打乱 CPU 内部为当前进程做的优化,比如缓存和流水线
+
+ 所以,切换太频繁会拖慢整体效率。好的调度,既要让大家都有机会跑,又要尽量减少无谓的切换。
+
+### 什么时候切换
+
+ 切换不会无缘无故发生,通常由这几件事引起:
+
+- **时间片用完**:一个进程跑了足够久,该让位了
+- **主动阻塞**:进程要等 I/O,主动让出 CPU
+- **被更高优先级的进程打断**:来了更要紧的事
+
+ 到这里,进程“轮流上 CPU”的机制就通了。可到底该让谁先上、上多久?这属于操作系统的另一个核心话题——**调度**。下一章,我们先看看调度要解决哪些矛盾。
+
+ **思考题**
+
+> 如果上下文切换不需要保存和恢复现场,直接让两个进程“混着跑”,会出什么问题?为什么“保存现场”是不可省略的一步?
## 小结
-- 上下文包括寄存器和其他执行相关状态。
-- 切换实现多任务,也带来开销。
+### 知识点
+
+- 上下文是进程的运行现场:PC、寄存器、栈等
+- 上下文切换:保存当前、选择下一个、恢复下一个
+- 切换是分时多任务的基础,但有开销
+- 切换常由时间片耗尽、阻塞或更高优先级打断引起
+
+### 参考资料
+
+1. [Wikipedia(zh):上下文切换](https://zh.wikipedia.org/wiki/%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2):context switch
+2. [Wikipedia(zh):进程控制块](https://zh.wikipedia.org/wiki/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%9D%97):现场的保存位置
### 思考题答案(仅供参考)
- 后续指令还依赖通用寄存器、栈、地址空间等状态;只恢复位置会让计算使用错误的数据。
+ 如果两个进程“混着跑”,它们会共用同一组寄存器和 PC:A 刚把一个中间结果放进寄存器,B 立刻把它覆盖掉;PC 也会在两条指令流之间乱跳。结果就是两边都算错。保存现场的意义,正是把每个进程的“进度”完整地存起来,互不覆盖;恢复现场,则是让它接着自己的进度继续。少了这一步,就没法把一个 CPU 安全地分给多个进程。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十四章:进程的创建与结束.md
+77 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
index 76b7b939..0a60183e 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\345\233\233\347\253\240\357\274\232\350\277\233\347\250\213\347\232\204\345\210\233\345\273\272\344\270\216\347\273\223\346\235\237.md"
@@ -1,35 +1,99 @@
-# 第五十四章:进程的创建与结束
+# 进程的创建与结束
## 复习
-- 进程是程序加上当前执行现场和资源。
+- 程序是静态文件,进程是正在运行的程序
+- 内核把程序装入内存,建立地址空间,标记为就绪
+- 进程不会凭空出现,也不会凭空消失
## TL;DR
-- 操作系统创建进程、装入程序,并在结束后回收资源。
-- 许多系统用父子关系组织创建与等待。
+- 进程通常由另一个进程创建,形成父子关系
+- 创建常常分两步:先复制一份(`fork`),再装入新程序(`exec`)
+- 进程结束时调用 `exit`,资源由内核回收
+- 退出状态要由父进程收取,否则会留下“僵尸进程”
## 正文
- 启动新程序时,内核要建立地址空间、准备初始栈和寄存器,并从可执行文件装入代码。类 Unix 系统常把“创建一个近似副本”和“用新程序替换其地址空间”拆成两步;不必记住具体接口,重要的是理解:进程创建和程序装入都是内核的工作。
+ 上一章说,内核能把程序变成进程。可内核自己并不主动去“造”进程——真正发起创建的,往往是一个已经存在的进程。
- 进程结束时,内核关闭它打开的资源、释放内存,并保存一个退出状态供创建者查询。父进程若尚未取走这个结果,内核还要暂留最小记录,避免结果无处可查。
+### 父与子
- 现在进程会出现和消失了。要同时管理许多进程,内核需要一份随时可查的档案,并用它描述进程正处于什么状态。
+ 在大多数操作系统里,创建进程的基本方式是:**当前进程调用系统调用,复制出一个新进程。**
-**思考题**
+ 被复制出来的叫**子进程**,原来的叫**父进程**。子进程几乎是父进程的翻版——同样的代码、同样的数据、同样的打开文件。之后,父子各走各的路,互不干扰。
-> 为什么进程退出后不能立刻忘掉全部信息?
+ 很多系统把这个过程拆成两步:
+
+1. **`fork`**:复制出一个和父进程几乎一样的子进程
+2. **`exec`**:在子进程里装入一个全新的程序,替换掉原来的代码和数据
+
+ “先克隆,再换人”——这样设计很灵活:可以先在克隆体里做些准备(比如重定向输入输出),再让它变成真正要跑的程序。
+
+### 结束
+
+ 进程干完活,会调用 `exit` 退出,并留下一个**退出状态**(比如 0 表示成功,非 0 表示出错)。
+
+ 但退出不等于“彻底消失”。进程占用的内存、文件等资源,需要内核来回收;而它的退出状态,得由父进程来“收尸”。
+
+ 如果父进程一直不去收,这个已经退出、却还没被清理的进程,就成了**僵尸进程**(zombie)。它不再运行,却还占着系统里的一条记录。反过来,如果父进程先退出了,留下的子进程会被系统接管,成为**孤儿进程**(orphan)。
+
+### 一条完整的生命周期
+
+```text
+父进程
+ │ fork:复制出子进程
+ ▼
+子进程
+ │ exec:装入新程序
+ ▼
+运行…… 父进程 wait:收取退出状态
+ │ exit:退出并留下状态 ▲
+ ▼ │
+等待被回收 ────────────────────────┘
+ │
+ ▼
+彻底消失
+```
+
+ 把这张图记住,就能理解很多现象:为什么启动一个程序,常常是“先复制、再替换”;为什么写服务器时,父进程要不停地“收”子进程,否则会攒一堆僵尸。
+
+### 进程树
+
+ 因为进程都是由别的进程创建的,整个系统里的进程其实构成一棵树:最顶上是一个“祖先进程”,下面分出子进程、孙进程……系统启动后,第一个进程就是这棵树的根。
+
+ 这棵树不是摆设。**权限、资源、信号**,很多都沿着父子关系传递。理解了“创建靠复制、结束靠回收”,也就理解了这棵树是怎么长起来、又怎么修剪的。
+
+ **思考题**
+
+> 既然 `fork` 出来的子进程和父进程几乎一模一样,为什么不干脆“创建一个空进程、再装程序”,而要绕一道“先复制”?这样的设计带来了哪些灵活之处?
## 小结
-- 创建涉及建立执行环境并装入程序。
-- 结束涉及释放资源和保留必要的退出结果。
+### 知识点
+
+- 进程由已有进程创建,形成父子关系
+- `fork` 复制进程,`exec` 装入新程序
+- `exit` 退出并留下退出状态
+- 父进程用 `wait` 收取状态,否则产生僵尸进程
+- 进程在系统中构成一棵树
+
+### 参考资料
+
+1. [Wikipedia(zh):fork](https://zh.wikipedia.org/wiki/Fork):创建进程的系统调用
+2. [Wikipedia(zh):exec](https://zh.wikipedia.org/wiki/Exec_(%E8%AE%A1%E7%AE%97%E6%9C%BA)):替换进程映像
+3. [Wikipedia(zh):僵尸进程](https://zh.wikipedia.org/wiki/%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B):僵尸与孤儿进程
### 思考题答案(仅供参考)
- 创建者可能还要知道它是否成功、为何失败;内核需暂存退出状态,直到有人领取。
+ “先复制、再替换”的妙处在于:克隆出来的子进程继承了父进程已准备好的上下文——打开的文件、设置的输入输出、环境变量等。父进程可以先在克隆体里调整这些,再让 `exec` 换成真正的程序。比如 shell 要运行一条命令并把它的输出重定向到文件,就可以先在子进程里改好输出方向,再替换成命令程序。若直接“创建空进程”,这些准备就得另想办法。多一步复制,换来的是组合上的极大灵活。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第五十章:操作系统是什么.md
+78 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
index f2041a06..7b8daeaf 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\344\272\224\345\215\201\347\253\240\357\274\232\346\223\215\344\275\234\347\263\273\347\273\237\346\230\257\344\273\200\344\271\210.md"
@@ -1,35 +1,100 @@
-# 第五十章:操作系统是什么
+# 操作系统是什么
## 复习
-- 内核被装入内存后,会先于普通程序开始工作。
+- 固件、引导程序、内核层层接力,把机器唤醒
+- 内核初始化后,开始接手管理机器
+- 之前裸机程序遇到的困难,正等着它来处理
## TL;DR
-- 操作系统既管理 CPU、内存和设备,也向程序提供较易使用的抽象。
-- 它不是某个窗口或桌面,而是一套协调硬件与程序的基础软件。
+- 操作系统有两个身份:**资源的管理者** 和 **抽象的提供者**
+- 作为管理者,它分配和回收 CPU、内存、设备、文件
+- 作为抽象者,它提供进程、文件、地址空间等好用的概念
+- 内核是操作系统的核心,常驻内存,程序通过它请求服务
## 正文
- 没有操作系统时,每个程序都要自己设置设备、保存数据、安排内存,也会彼此踩坏对方。操作系统把这些反复出现的事务集中起来:它决定谁暂时使用 CPU,记录哪块内存属于谁,协调磁盘和键盘等设备。
+ 启动的接力跑完了,管理者终于上位。这个管理者,就是我们一直在说的**操作系统**(operating system)。可它到底“是什么”?
- 同时,它把难用的硬件细节包装成更方便的对象。程序不必知道磁盘扇区位置,只需打开“文件”;不必轮询网卡寄存器,只需读写“套接字”。这正是总览里所说的“加一层”:底层仍在,但大多数程序不必反复处理它。
+ 与其背定义,不如看它干的活。操作系统有两副面孔。
- 不过,管理者若没有边界,普通程序仍可能随意破坏全局资源。下一章先建立一条硬件支持的权限分界线。
+### 面孔一:资源的管理者
-**思考题**
+ 上一部分末尾,我们列过裸机的几大麻烦:多个程序抢 CPU、抢内存、抢设备,谁先谁后,谁多谁少。这些正是操作系统的本职工作。
-> 文件为什么可以看作操作系统提供的抽象?
+ 计算机里的资源就那么几样:**CPU 时间、内存、设备、以及存在设备上的数据**。操作系统要做的是:
+
+- 分配:谁需要,就给谁一份
+- 回收:谁用完了,就收回来
+- 保护:不许任何人独占一切,也不许互相破坏
+- 记录:哪些已被占用,哪些还空着
+
+ 它像一位调度员,手里攥着有限的资源,尽量让每一件事都办得又快又公平。
+
+### 面孔二:抽象的提供者
+
+ 可光会“分东西”还不够。硬件本身又乱又难用:磁盘有一堆位置和格式,CPU 会不停地被打断,内存是一大片地址。直接把这些丢给程序,程序会很痛苦。
+
+ 于是操作系统又添了另一副面孔:**提供抽象**。
+
+- **文件**:把“硬盘上某处的若干数据块”包装成“一个有名字、能读写的对象”
+- **进程**:把“一小段正在用 CPU 的代码”包装成“一个正在运行的程序”
+- **地址空间**:把“散落各处的物理内存”包装成“每个程序独占的一整片连续内存”
+
+ 程序只要会用这些概念,就不必再操心磁盘、中断和物理地址。这就是我们反复见到的**加一层**:在最难看的硬件和最上层的程序之间,操作系统搭了一层又好用又安全的抽象。
+
+### 内核
+
+ 操作系统里最核心、也最常驻内存的那部分,叫**内核**(kernel)。程序想要读文件、发数据、申请内存,最终都是在内核里完成的。
+
+ 内核之外的软件(比如各种库、工具、图形界面)则站在内核肩膀上,一起构成我们平时说的“操作系统”。所以“操作系统”既指那个核心,也常用来指整套软件。
+
+### 合起来看
+
+```text
+ 普通程序 / 工具 / 图形界面
+ │ 用进程、文件、地址空间
+ ┌────────▼────────┐
+ │ 内核 │ 管理 CPU、内存、设备
+ └────────┬────────┘
+ │
+ 硬件
+```
+
+ 管理者、抽象者,其实是同一件事的两面:**把混乱的硬件,整理成程序能用、敢用的样子。**
+
+ 既然内核这么重要,那程序是不是可以随意指挥它、让它替自己做任何事?当然不行。下一章,我们要给机器划出一条界线:**内核态与用户态**。
+
+ **思考题**
+
+> “文件”是一种抽象。如果不用文件,程序直接操作磁盘上的数据块,会多出哪些麻烦?操作系统提供的抽象,是“取消了”硬件细节,还是“隐藏”了硬件细节?
## 小结
-- 操作系统管理资源,也提供抽象。
-- 内核是其中直接掌管关键资源的部分。
+### 知识点
+
+- 操作系统是资源的管理者,负责分配、回收与保护
+- 操作系统是抽象的提供者,给出文件、进程、地址空间等概念
+- 内核是操作系统的核心,常驻内存
+- 操作系统在硬件与程序之间加了一层
+
+### 参考资料
+
+1. [Wikipedia(zh):操作系统](https://zh.wikipedia.org/wiki/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F):操作系统的职责
+2. [Wikipedia(zh):内核](https://zh.wikipedia.org/wiki/%E5%86%85%E6%A0%B8):内核的组成
+3. [Wikipedia(zh):系统资源](https://zh.wikipedia.org/wiki/%E7%B3%BB%E7%BB%9F%E8%B5%84%E6%BA%90):资源管理
### 思考题答案(仅供参考)
- 程序通过名字和读写操作使用文件,不必理解磁盘的物理布局与控制命令。
+ 不用文件,程序就得自己记住数据放在磁盘的哪个磁道、哪个扇区,自己处理读写命令、错误重试和空间回收,稍微换个设备还得重写。操作系统提供的文件抽象,并没有取消这些硬件细节,而是把它们隐藏起来:细节还在,只是由内核统一替你面对。这也正是抽象的一贯做法——不消灭复杂,只把复杂挡在接口之后。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十一章:多核调度(进阶).md
+73 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
index f37c9115..8421563f 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\270\200\347\253\240\357\274\232\345\244\232\346\240\270\350\260\203\345\272\246\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -1,35 +1,95 @@
-# 第六十一章:多核调度(进阶)
+# 多核调度
+
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
## 复习
-- 调度器可用反馈和优先级在一个 CPU 上选择任务。
+- 调度决定谁上 CPU、跑多久
+- 时间片、优先级、老化共同平衡响应与公平
+- 到目前为止,我们默认只有一个 CPU
## TL;DR
-- 多核调度还要决定任务在哪个核心运行。
-- 负载均衡与缓存亲和性常彼此拉扯。
+- 多核系统里,调度器要决定的不只是“跑谁”,还有“在哪跑”
+- 负载均衡:别让一个核忙死、另一个核闲着
+- 缓存亲和性:尽量让进程待在同一个核上,复用它的缓存
+- 均衡与亲和互相拉扯,需要折中
## 正文
- 多个核心可以真正并行执行不同进程。调度器要避免一个核心空闲、另一个核心排长队,这叫**负载均衡**。它可以共享就绪队列,也可以让每个核心有自己的队列并在必要时“偷取”任务。
+ 现代计算机的 CPU 里往往不止一个核心(还记得前面讲并行时提到的多核吗)。于是调度多了一个新问题:**任务该放到哪个核上跑?**
+
+### 不只是“跑谁”
+
+ 单核时代,就绪队列是一条,调度器挑一个出来跑就行。多核时代,每个核都需要一个任务,于是:
+
+- 每个核都有自己的就绪队列,或者共享一个全局队列
+- 调度器要保证每个核都不闲着,同时又不抢同一个任务
+
+ 如果分配不均,就会出现一个核排着长队、另一个核无所事事。这就是**负载均衡**要解决的问题。
+
+### 迁移的代价
+
+ 一个很自然的想法是:哪个核闲,就把任务挪过去。但把任务从 A 核搬到 B 核,是有代价的:
+
+- 任务在 A 核上积累的缓存内容,到了 B 核用不上(缓存是每个核自己的)
+- 迁移本身也要做上下文切换
+
+ 所以,**能不动就不动**。
+
+### 缓存亲和性
+
+ 由此引出**缓存亲和性**(cache affinity):一个进程在某个核上跑得越久,它的数据和指令就越可能留在这个核的缓存里。下次还让它在这个核上跑,就能直接命中缓存,快得多;换来换去,则每次都要重新“预热”缓存。
- 但频繁迁移任务并不总是好事。一个进程刚用过的数据仍可能留在某个核心的缓存中;继续留在原核心能少等内存,这种倾向叫**缓存亲和性**。调度器需要在均衡与亲和之间折中。
+ 所以调度器倾向于:**让进程尽量待在原来的核上。**
- 多个核心也意味着同一进程内可以同时推进多条执行线。线程由此出现。
+### 均衡与亲和的拉扯
-**思考题**
+ 可“尽量不迁移”又和“负载均衡”冲突:死守亲和,可能出现某个核累死、某个核闲着。
-> 为什么把任务平均分配到核心后仍可能变慢?
+ 现实的调度器,通常这样折中:
+
+- 平时尊重亲和,尽量让任务留在原核
+- 当某些核明显过载、另一些明显空闲时,才把任务迁过去
+- 定期做一次“再平衡”,但不频繁迁移
+
+```text
+核 1:████████ 忙
+核 2:██ 闲 ← 触发一次迁移
+核 1:█████ 较忙
+核 2:█████ 较忙
+```
+
+ 一句话:**多核调度是在“让大家都别闲着”和“别把任务搬来搬去”之间找平衡。**
+
+ **思考题**
+
+> 如果一个进程每隔几毫秒就在两个核之间来回迁移,会带来哪些额外开销?为什么“缓存亲和性”对性能影响这么大?
## 小结
-- 多核调度增加了核心选择与负载均衡问题。
-- 缓存亲和性使迁移具有代价。
+### 知识点
+
+- 多核调度要决定“跑谁”和“在哪跑”
+- 负载均衡:让每个核都不空闲
+- 缓存亲和性:让进程尽量留在同一核
+- 均衡与亲和互相冲突,需要折中
+
+### 参考资料
+
+1. [Wikipedia(zh):多处理器调度](https://zh.wikipedia.org/wiki/%E5%A4%9A%E5%A4%84%E7%90%86%E5%99%A8%E8%B0%83%E5%BA%A6):多核调度
+2. [Wikipedia(zh):CPU 缓存](https://zh.wikipedia.org/wiki/CPU%E7%BC%93%E5%AD%98):缓存与局部性
### 思考题答案(仅供参考)
- 迁移会丢失原核心缓存中的局部性,新的核心可能需要重新从较慢内存取数据。
+ 频繁迁移有两个主要开销:一是每次迁移都要做上下文切换,并可能让原核的缓存内容白费;二是到了新核,缓存里没有该进程的数据和指令,需要重新从内存加载,命中率骤降。进程刚“预热”好一个核的缓存,又被搬走,等于反复从头开始。所以缓存亲和性对性能影响很大——它决定了一个进程能不能持续吃到“热”的缓存。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+.png)
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十二章:线程与并发.md
+68 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
index deba4a2a..b601e879 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\344\272\214\347\253\240\357\274\232\347\272\277\347\250\213\344\270\216\345\271\266\345\217\221.md"
@@ -1,35 +1,90 @@
-# 第六十二章:线程与并发
+# 线程与并发
## 复习
-- 多核允许不同任务真正同时运行。
+- 进程是正在运行的程序,拥有独立的地址空间
+- 内核通过调度让多个进程轮流使用 CPU
+- 进程之间彼此隔离,互不干扰
## TL;DR
-- 线程是进程内部的一条执行线。
-- 同一进程的线程共享地址空间,却各有寄存器和栈。
+- **线程**是进程内部的一条执行线,一个进程可以有多条
+- 同一进程的线程共享地址空间和资源,各自有寄存器和栈
+- **并发**是“看起来同时”,**并行**是“真的同时”
+- 线程更轻、切换更省,但共享内存也让它们更容易互相干扰
## 正文
- 浏览器下载网页时仍要响应点击,程序可把这些工作交给不同**线程**。进程提供资源和地址空间;线程提供独立的执行位置、寄存器现场和运行栈。同一进程的线程能轻易看到共同变量,也因此更容易彼此干扰。
+ 一个文本编辑器,既要响应你的按键,又要在后台自动保存文件。它是怎么“同时”做两件事的?
- **并发**指多项工作在时间上交错推进,即使只有一个核心也成立;**并行**指它们此刻真的在不同核心同时执行。并发让程序结构更贴近独立任务,并行才可能带来同时计算的速度提升。
+ 你可能会说:开两个进程不就行了。可进程之间是隔离的——共享一段数据要费不少周折,创建和切换的开销也不小。于是,人们想在**同一个进程内部**,分出几条并行的执行线。
- 不同进程不能天然共享变量,它们又该怎样交换信息?
+### 进程里的多条执行线
-**思考题**
+ 这个“执行线”,就是**线程**(thread)。
-> 同一进程的线程为什么通常不必复制整份代码和全局数据?
+ 一个进程可以包含多个线程。它们共享同一个地址空间、同一批打开的文件、同样的全局数据;但每个线程有自己独立的**寄存器和栈**——因为每条执行线都要记住自己跑到哪了。
+
+```text
+进程
+ ├── 地址空间、打开的文件(共享)
+ ├── 线程 1:寄存器 + 栈
+ ├── 线程 2:寄存器 + 栈
+ └── 线程 3:寄存器 + 栈
+```
+
+ 好比一间办公室:办公桌、文件柜、打印机(地址空间、资源)是所有员工(线程)共用的;但每个人手头正在做的事(寄存器、栈)各不相同。
+
+### 并发与并行
+
+ 这里要分清两个容易混的词:
+
+- **并发**(concurrency):多个任务在**一段时间内**都在推进,看起来像同时,但可能是在一个核上快速切换出来的
+- **并行**(parallelism):多个任务在**同一时刻**真的各占一个核,同时执行
+
+ 一个核也能“并发”——靠时间片切换,你几乎察觉不到;但真正的“并行”,需要多个核。二者不是一回事。
+
+### 线程的利与弊
+
+ 线程的好处很直接:
+
+- **轻量**:创建、切换只涉及寄存器和栈,比整个进程便宜
+- **方便共享**:同一进程的线程天然共享数据,不必像进程那样绕来绕去
+- **响应好**:一个线程在等 I/O 时,别的线程可以继续干活
+
+ 可共享是一把双刃剑。正因为线程共用同一片内存,它们很容易**互相踩脚**:两个线程同时改同一个变量,可能算错;一个线程崩溃,整个进程都可能遭殃。
+
+ 这正是“并发”话题的由来:一旦允许多条执行线共享数据,我们就得想办法让它们**不冲突**。这部分内容,从下一章起会连着讲好几章。
+
+ **思考题**
+
+> 一个进程的多个线程共享地址空间,只在寄存器和栈上各自独立。为什么“栈”必须每个线程一份,而不能共享?
## 小结
-- 线程共享进程资源,拥有各自执行现场。
-- 并发不等于并行。
+### 知识点
+
+- 线程是进程内的执行线,一个进程可有多个
+- 线程共享地址空间和资源,各有寄存器和栈
+- 并发是“看起来同时”,并行是“真的同时”
+- 线程轻量、便于共享,但共享也带来冲突风险
+
+### 参考资料
+
+1. [Wikipedia(zh):线程](https://zh.wikipedia.org/wiki/%E7%BA%BF%E7%A8%8B):线程的概念
+2. [Wikipedia(zh):并发计算](https://zh.wikipedia.org/wiki/%E5%B9%B6%E5%8F%91%E8%AE%A1%E7%AE%97):并发与并行的区别
+3. [Wikipedia(zh):并行计算](https://zh.wikipedia.org/wiki/%E5%B9%B6%E8%A1%8C%E8%AE%A1%E7%AE%97):并行计算
### 思考题答案(仅供参考)
- 这些内容属于同一个进程的地址空间,线程本来就在其中运行;只需各自保存栈和寄存器等私有状态。
+ 栈记录的是“这条执行线自己的调用过程”:函数调到哪里、局部变量是什么、返回地址在哪。每条执行线走的函数、想返回的地方都不一样,必须各存一份,否则两条线会互相覆盖对方的返回地址,一返回就跳错地方。而堆、全局数据这类“大家都要用”的内容,才适合共享。所以“共享地址空间、各自独立栈”的分工,恰好对应了“资源共用、执行独立”。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第六十章:多级反馈队列(进阶).md
+68 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
index da6ed567..ad9759aa 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\205\255\345\215\201\347\253\240\357\274\232\345\244\232\347\272\247\345\217\215\351\246\210\351\230\237\345\210\227\357\274\210\350\277\233\351\230\266\357\274\211.md"
@@ -1,35 +1,90 @@
-# 第六十章:多级反馈队列(进阶)
+# 多级反馈队列
+
+> 本章为进阶内容,零基础读者可以跳过,不影响后续阅读。
## 复习
-- 时间片和优先级改善响应,却不知道每个任务的真实长度。
+- 时间片保证人人轮得到,优先级保证重要的先跑
+- 但优先级会带来饥饿,需要老化来补救
+- 调度器往往事先并不知道每个任务要跑多久
## TL;DR
-- 多级反馈队列依据任务近期行为动态调整优先级。
-- 它倾向先服务短小、交互频繁的任务,也必须避免长期任务被饿死。
+- 多级反馈队列用多个优先级队列,让进程“先高后低”地浮动
+- 新进程从高优先级开始,用完时间片还没完,就降到下一级
+- 短任务在高优先级迅速完成,长任务逐级下沉,不必事先知道长短
+- 它是“自动适应任务长短”的一种巧妙设计
## 正文
- **多级反馈队列**准备多个优先级队列。新任务常从高优先级开始;若它很快因等待输入而让出 CPU,说明可能是交互任务,可以继续保持较高优先级;若它反复用完时间片,则逐步下调,给短任务更多机会。
+ 前面几种调度,要么要求“知道任务要跑多久”,要么需要人手工设定优先级。可现实中,调度器往往两眼一抹黑:来的到底是几毫秒的小任务,还是几小时的大家伙?
+
+ **多级反馈队列**(MLFQ,Multi-Level Feedback Queue)就是为这种“未知”而生的。
+
+### 多个队列,先高后低
+
+ MLFQ 设置多个就绪队列,每个队列有不同的优先级:
+
+```text
+高优先级 Q0 ← 新进程从这里开始
+ Q1
+ Q2
+低优先级 Q3
+```
+
+ 规则大致是这样的:
+
+- **新进程先进入最高优先级的队列**
+- 同一队列内,用时间片轮转
+- 一个进程用完自己的时间片还没结束,就**降到下一级队列**
+- 只有高优先级队列空了,才轮到低优先级队列
+
+### 它为什么聪明
+
+ 这套规则的效果很妙:
+
+- **短任务**:一上来就在高优先级,往往一两个时间片就跑完了,很快离开系统
+- **长任务**:占用 CPU 的时间越来越长,于是逐级下沉,把高优先级让给新来的短任务
+- **交互任务**:经常等 I/O、很少用满时间片,于是能一直待在较高优先级,保持响应
- 这不是预先知道任务长度,而是根据观察不断修正判断。为了不让计算密集型任务永久沉底,系统会周期性提升等待很久的任务,或限制高优先级任务的连续占用。
+ 换句话说,它**不用事先知道任务的长短,而是通过“观察它用了多少 CPU”来推断**:总是很快就让出 CPU 的,多半是短任务或交互任务,给它高优先级;一直霸着 CPU 的,多半是长任务,把它压下去。
- 一个 CPU 已经能轮流服务很多任务。现代机器通常有多个核心,轮流之外又多了分配问题。
+### 别忘了老化
-**思考题**
+ 不过,如果高优先级源源不断地来新任务,长任务会被一直压在最底层,又出现**饥饿**。所以 MLFQ 通常还要配一条**老化**规则:低优先级队列里的进程,等得够久,就把它升回高一级;或者定期把所有进程都提到最高优先级,重新洗一次牌。
-> 任务频繁等待输入,为什么常被视为值得优先响应的信号?
+### 一句话总结
+
+ MLFQ 把“优先级”变成了一个**动态的、会自我调整**的东西:谁表现得像短任务,谁就享受高优先级;谁表现得像长任务,谁就退居二线。它不需要预知,也不需要人工调参,是许多真实操作系统调度器的思想来源。
+
+ **思考题**
+
+> 一个交互程序,每跑一小会儿就要等一次键盘输入;另一个是长时间计算的任务。它们在 MLFQ 里,大致会分别停在哪一级?为什么?
## 小结
-- 反馈队列用运行行为近似推测任务类型。
-- 防饥饿仍是设计中的必要约束。
+### 知识点
+
+- 多级反馈队列:多个优先级队列
+- 新进程从高优先级开始,用满时间片则降级
+- 通过“用 CPU 多少”间接推断任务长短
+- 需要老化来防止长任务饥饿
+
+### 参考资料
+
+1. [Wikipedia(zh):多级反馈队列](https://zh.wikipedia.org/wiki/%E5%A4%9A%E7%BA%A7%E5%8F%8D%E9%A6%88%E9%98%9F%E5%88%97):MLFQ
+2. [Wikipedia(zh):调度_(计算)](https://zh.wikipedia.org/wiki/%E8%B0%83%E5%BA%A6_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)):调度算法综述
### 思考题答案(仅供参考)
- 这类任务往往直接对应人的操作;尽快继续运行能减少可感知的等待。
+ 交互程序会在较高优先级。因为它经常等待输入,很少用满时间片,不会被降级;而每次等待结束、重新就绪时,又往往能排到靠前的位置。长时间计算任务则会逐渐沉到较低优先级,因为它总是用满时间片、被一次次降级。只有当高优先级没有别的任务、或老化机制把它提上来时,长任务才会重新获得较高优先级。这正是 MLFQ “按表现分配优先级”的体现。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+.png)
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第四十九章:引导程序与内核加载.md
+74 / -14 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
index 39412ce6..cd0f237f 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\344\271\235\347\253\240\357\274\232\345\274\225\345\257\274\347\250\213\345\272\217\344\270\216\345\206\205\346\240\270\345\212\240\350\275\275.md"
@@ -1,39 +1,99 @@
-# 第四十九章:引导程序与内核加载
+# 引导程序与内核加载
## 复习
-- 固件从固定位置开始,负责寻找下一段可运行的软件。
+- 上电复位后,CPU 从固定地址开始执行
+- 固件负责自检并找到启动设备
+- 固件把控制权交给启动设备上的引导程序
## TL;DR
-- 引导程序把操作系统内核从持久存储读入内存并跳转过去。
-- 启动被拆成阶段,是因为最早的代码只能使用很少的资源。
+- 引导程序的任务:把操作系统内核从磁盘装进内存,再跳过去
+- 它比固件大、比内核小,仍然要小而可靠
+- 内核被装入并初始化后,才真正接手管理机器
+- 到这一步,启动的接力才算交到管理者手里
## 正文
- 磁盘中的操作系统内核很大,固件却很小,也未必懂所有磁盘格式。因此启动通常分阶段进行:固件找到一个小型**引导程序**;引导程序初始化更多硬件,读入更完整的引导器;最后由它把**内核**装到内存的合适位置,准备参数并跳转到内核入口。
+ 上一章,固件从启动设备里只读了一小段代码,就跳了过去。真正的操作系统内核,还好好躺在磁盘上。
+
+ 把内核请进内存的活儿,就落在这一棒——**引导程序**(bootloader)身上。
+
+### 它为什么这么小
+
+ 固件给引导程序的空间通常非常有限:老式机器上,只有磁盘的第一个扇区,几百字节。就这么点地方,既要能读磁盘,又要能找内核,实在逼仄。
+
+ 所以引导程序常常分两步走:
+
+1. 先利用这一小段空间,把磁盘上更大的一段引导代码读进来
+2. 再由这段代码,去完成真正的加载工作
+
+ 这一步一步地“把自己变大”,是引导程序里的常见套路。
+
+### 把内核搬进来
+
+ 接下来,引导程序要顺着磁盘上的位置,把**内核映像**读进内存的指定位置。
+
+ 内核是一个完整的程序,有代码、有数据,可能还有压缩包和自己的一小段解压代码。引导程序负责把它原样搬到内存里预先约好的地方。
```text
-上电 → 固件 → 引导程序 → 内核 → 普通程序
+磁盘: [ 引导程序 ][ 内核映像 ][ 其它文件 ]
+内存: ↑ ↑
+ 执行它 搬到内存约定位置
```
- 这个过程和第 45 章的装载相呼应,只是此刻还没有操作系统可帮忙。引导器必须自己读设备、安排内存。内核接管之后,才有一段长期驻留的软件来重复处理这些工作。
+ 搬完之后,引导程序让 PC 指向内核的入口地址,跳过去。从这一刻起,机器开始跑内核的代码——启动的控制权,正式交接。
+
+### 内核初始化
+
+ 内核接手时,机器还是一片“荒地”:内存管理没建立,设备没接好,中断没配置。所以它要先做一串初始化:
+
+- 建立内存管理,弄清哪些内存可用
+- 设置中断和异常处理
+- 初始化设备与驱动
+- 建立起调度所需的数据结构
- 内核为何值得如此郑重地先启动?因为它将成为所有程序共享硬件时的管理者。
+ 收拾停当后,内核启动第一个进程。从此以后,程序不再直接面对硬件,而是通过内核请求服务——这正是我们下一章要说的“管理者”。
-**思考题**
+### 接力完成
-> 为什么不直接把完整内核写进固件?
+ 把整条链子连起来看:
+
+```text
+固件 → 引导程序 → 内核初始化 → 第一个进程 → 普通程序
+```
+
+ 每一棒都只干一件事:把下一棒读进来、跳过去。硬件千差万别,但这条接力链环环相扣,最终把控制权稳稳地交到了操作系统手里。
+
+ **思考题**
+
+> 引导程序为什么要“尽量小”?如果它出了错,机器会怎样?为什么启动过程要分成固件、引导程序、内核这么多棒,而不是一步到位?
## 小结
-- 引导程序把内核从持久存储装入内存。
-- 分阶段启动逐步获得更多硬件能力。
+### 知识点
+
+- 引导程序负责把内核从磁盘装入内存并跳转
+- 引导程序常常分两阶段,逐步扩大自身
+- 内核初始化内存、中断、设备与调度结构
+- 启动是固件、引导程序、内核层层接力的过程
+
+### 参考资料
+
+1. [Wikipedia(zh):启动程序](https://zh.wikipedia.org/wiki/%E5%90%AF%E5%8A%A8%E7%A8%8B%E5%BA%8F):bootloader 的工作
+2. [Wikipedia(zh):内核](https://zh.wikipedia.org/wiki/%E5%86%85%E6%A0%B8):操作系统内核
+3. [Wikipedia(zh):多重引导](https://zh.wikipedia.org/wiki/GNU_GRUB):常见的引导程序
### 思考题答案(仅供参考)
- 内核较大且经常更新;放在磁盘等设备中更灵活,固件只需保留稳定的最小启动能力。
+ 引导程序要小,是因为固件给它的空间很有限,而且越小越不容易出错、加载越快。它一旦出错,后续的内核就装不进来,机器会卡在启动阶段,通常表现为黑屏或反复重启。启动之所以分成好几棒,是因为每一步面对的限制不同:固件要在硬件差异巨大的情况下找到启动设备,引导程序要在很小的空间里搬动内核,内核则要建立完整的运行环境。分工明确、逐级抽象,才让“从按下电源到运行程序”这件复杂的事变得可靠。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪
src/学习与进步/计算机科学极简入门指南/操作系统/第四十八章:按下电源:复位与固件.md
+73 / -13 Click to expand diff
diff --git "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md" "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
index 827e5b7d..92157592 100644
--- "a/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
+++ "b/src/\345\255\246\344\271\240\344\270\216\350\277\233\346\255\245/\350\256\241\347\256\227\346\234\272\347\247\221\345\255\246\346\236\201\347\256\200\345\205\245\351\227\250\346\214\207\345\215\227/\346\223\215\344\275\234\347\263\273\347\273\237/\347\254\254\345\233\233\345\215\201\345\205\253\347\253\240\357\274\232\346\214\211\344\270\213\347\224\265\346\272\220\357\274\232\345\244\215\344\275\215\344\270\216\345\233\272\344\273\266.md"
@@ -1,35 +1,95 @@
-# 第四十八章:按下电源:复位与固件
+# 按下电源:复位与固件
## 复习
-- 裸机程序必须自己从约定地址开始,并直接面对硬件。
+- 裸机程序必须自己解决装载、设备和多程序共存
+- 这些麻烦需要一个管理者来统一处理
+- 现在,我们从头看看这位管理者是怎样登场的
## TL;DR
-- CPU 上电后会进入确定的初始状态,并从固定位置取第一条指令。
-- 固件是预先存放在非易失性存储器中的第一段软件。
+- 按下电源的一瞬间,机器里还没有操作系统
+- CPU 只能从约定好的固定地址取第一条指令,这叫复位
+- 这段最先运行的软件叫固件,负责自检并找到启动设备
+- 固件把控制权交给启动设备上的引导程序,接力正式开始
## 正文
- 按下电源并不会让操作系统凭空出现。电路稳定后,CPU 会经历**复位**:寄存器被放入规定初值,程序计数器指向架构约定的启动位置。它随后取出的第一条指令,来自一段早已放好的软件。
+ 按下电源键,机器“嗡”地一声亮起来。可这一刻,它其实什么都不知道——内存是空的,操作系统还没被装进去。
- 这段软件叫**固件**。它通常保存在断电仍能留住内容的闪存中,负责检查最基本的硬件、找到可启动设备,并把控制权交给下一阶段。它像建筑开工前先搭好的脚手架:功能有限,却让后面的复杂软件有了落脚处。
+ 那么,CPU 该从哪里开始执行?
- 固件不能知道每个用户想运行哪个程序,所以它只解决“怎样找到并启动一个系统”。下一步,专门负责把操作系统送进内存的引导程序登场。
+### 从一个约定好的地址开始
-**思考题**
+ 这是计算机启动的第一条规矩:**上电之后,CPU 从一个固定的地址取第一条指令。**
-> 如果 CPU 上电后没有约定的第一条指令地址,会出现什么问题?
+ 这个动作叫**复位**(reset):把所有寄存器设成初始值,让 PC 指向那个约定地址。全世界的 CPU 和主板都遵守这个约定,不然第一行代码就无从谈起。
+
+ 那个地址里放的,是主板上一小块**只读存储器**中的程序。它通常被称为**固件**(firmware),大家更熟悉的名字是 BIOS 或 UEFI。
+
+### 固件做三件事
+
+ 固件是最先醒来的软件,它大致做三件事:
+
+1. **自检**:检查内存、显卡、键盘等基本设备是否正常(俗称 POST)
+2. **初始化**:给硬件做最基本的设置
+3. **寻找启动设备**:按照预设顺序,在硬盘、U 盘、光驱里找“可以启动”的那个
+
+ 它像新兵连的班长:天没亮先把大家叫起来,点名、发装备,再告诉你接下来听谁的。
+
+### 找到启动设备
+
+ 光靠固件是装不下操作系统的:它容量有限,而且改动起来很麻烦。所以,固件并不亲自加载操作系统,而是去找一个**启动设备**。
+
+ 它在设备的固定位置读取一小段代码,把控制权从自己手里**交给**这段代码——这就是**引导程序**(bootloader)。交接的方式很简单:让 PC 跳过去。
+
+ 于是,启动就成了一条接力链:
+
+```text
+固件 → 引导程序 → 操作系统内核 → 普通程序
+```
+
+ 每一棒都只做一件事:从下一棒该在的位置把它读进来,然后跳过去。
+
+### 为什么这么绕
+
+ 你可能会问:既然操作系统在硬盘上,为什么不让 CPU 直接去硬盘执行?
+
+ 因为 CPU 只能执行内存里的指令;而且硬盘的位置、格式千差万别,CPU 并不认识。固件和引导程序,正是为了在“硬件千差万别”和“内核只认内存”之间搭一座桥。
+
+ 这又是那句话:**在计算机科学里,没有什么问题是加一层解决不了的。**
+
+ 固件把控制权交出去之后,引导程序要做的事情还不少:它得把真正的内核从硬盘搬进内存。下一章,我们就看这一棒怎么跑。
+
+ **思考题**
+
+> 固件和操作系统都“管理硬件”,它们的职责有什么不同?为什么不让固件直接把整个操作系统也一起装好?
## 小结
-- 复位给 CPU 一个确定起点。
-- 固件是开机后最先运行的软件。
+### 知识点
+
+- 复位:上电后 CPU 从固定地址开始执行
+- 固件:最先运行的软件,负责自检与寻找启动设备
+- 启动设备:存放引导程序的设备
+- 启动是一条接力的链条
+
+### 参考资料
+
+1. [Wikipedia(zh):固件](https://zh.wikipedia.org/wiki/%E5%9B%BA%E4%BB%B6):BIOS 与 UEFI
+2. [Wikipedia(zh):加电自检](https://zh.wikipedia.org/wiki/%E5%8A%A0%E7%94%B5%E8%87%AA%E6%A3%80):POST
+3. [Wikipedia(zh):引导程序](https://zh.wikipedia.org/wiki/%E5%90%AF%E5%8A%A8%E7%A8%8B%E5%BA%8F):bootloader
### 思考题答案(仅供参考)
- CPU 无法决定应从哪里取指令,启动过程也就没有共同的开始。
+ 固件只负责“把机器唤醒、把下一棒叫出来”,做的是最基本的、与具体操作系统无关的工作;操作系统则负责运行中的资源管理、进程调度、文件系统等。固件容量小、改动不便,也不适合承担复杂而多变的管理职责。把复杂的事情交给可替换、可升级的操作系统,固件只做“引路人”,职责更清晰,也更容易更新。
## 协议
-本文采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 协议发布。
+ 本作品采用[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh)进行许可。
+
+## 封面图
+
+
+
+> 设计师 | 南国微雪