|
32 | 32 |
|
33 | 33 | 进程控制块(Process Control Block,PCB)是操作系统中用于描述进程的一种数据结构,它包含了进程的所有信息。 |
34 | 34 |
|
35 | | -在实验中使用 `Process` 结构体表示一个进程,它含有 `pid` 和 `inner` 两个字段,分别表示进程的 ID 和内部数据。`inner` 字段是一个 `Arc<RwLock<ProcessInner>>` 类型的智能指针,它指向了一个 `ProcessInner` 结构体,这个结构体包含了进程的其他信息,包括进程的状态、调度计次、退出返回值、内存空间、父子关系、中断上下文、文件描述符表等等。 |
| 35 | +在实验中使用 `Process` 结构体表示一个进程,它含有 `pid` 和 `inner` 两个字段,分别表示进程的 ID 和内部数据。`inner` 字段是一个 `RwLock<ProcessInner>` 类型的字段,它包含了一个 `ProcessInner` 结构体,这个结构体包含了进程的其他信息,包括进程的状态、调度计次、退出返回值、内存空间、父子关系、中断上下文、文件描述符表等等。 |
36 | 36 |
|
37 | 37 | ??? note "`RwLock` 读写锁" |
38 | 38 |
|
39 | 39 | `RwLock` 读写锁允许多个线程同时读取数据,但只允许一个线程写入数据。 |
40 | 40 |
|
41 | 41 | 多个线程可以同时通过 `read()` 获取读锁,对数据进行读取操作,但只有一个线程可以通过 `write()` 获取写锁,对数据进行写入操作。当有线程获取写锁时,所有的读锁都会被阻塞,直到写锁被释放。 |
42 | 42 |
|
43 | | -??? note "`Arc` 原子引用计数智能指针" |
44 | | - |
45 | | - `Arc` 是 `alloc::sync` 中的一个原子引用计数智能指针,它允许多个线程同时拥有对同一数据的所有权,且不会造成数据竞争。 |
46 | | - |
47 | | - `Arc` 的 `clone()` 方法会增加引用计数,`drop()` 方法会减少引用计数,当引用计数为 0 时,数据会被释放。`Arc` 本身是**不可变的**,但可以通过 `RwLock` 获取内部可变性,进而安全的修改一个被多个线程所持有的数据。 |
48 | | - |
49 | 43 | 进程有一个唯一标识符:`pid`,实验使用 `struct ProcessId(pub u16)` 进行实现,在最基本的实现中,只需要保证每一次 `ProcessId::new()` 调用都会返回一个不同的 `ProcessId` 即可。 |
50 | 44 |
|
51 | 45 | 对于 `ProcessInner` 结构体,在后面的实验中将逐步补全和解释它的实现。 |
@@ -194,6 +188,12 @@ pub struct ProcessManager { |
194 | 188 | } |
195 | 189 | ``` |
196 | 190 |
|
| 191 | +??? note "`Arc` 原子引用计数智能指针" |
| 192 | + |
| 193 | + `Arc` 是 `alloc::sync` 中的一个原子引用计数智能指针,它允许多个线程同时拥有对同一数据的所有权,且不会造成数据竞争。 |
| 194 | + |
| 195 | + `Arc` 的 `clone()` 方法会增加引用计数,`drop()` 方法会减少引用计数,当引用计数为 0 时,数据会被释放。`Arc` 本身是**不可变的**,但可以通过 `RwLock` 获取内部可变性,进而安全的修改其中持有的数据。 |
| 196 | + |
197 | 197 | 其中 `processes` 字段用于存储所有的进程,`ready_queue` 字段则用于存储就绪的进程队列。`ProcessManager` 结构体被设计为“不可变”的,也就是说,它由 `RwLock` 和 `Mutex` 来提供内部可变性。 |
198 | 198 |
|
199 | 199 | ??? hint "`HashMap` 与 `ahash`" |
@@ -305,9 +305,9 @@ pub fn new(init: Arc<Process>) -> Self { |
305 | 305 |
|
306 | 306 | !!! note "缺页异常?" |
307 | 307 |
|
308 | | - 你可能会注意到,4GiB 的栈空间中实际映射的目前只有 2MiB,剩下的页面都是没有映射的。 |
| 308 | + 你可能会注意到,4GiB 的栈空间中实际映射的目前只有 2MiB,剩下的页面都是没有映射的。 |
309 | 309 |
|
310 | | - 在未来的实验内容中,你将会处理这种缺页异常,并在需要时为进程进行映射。 |
| 310 | + 在未来的实验内容中,你将会处理这种缺页异常,并在需要时为进程进行映射。 |
311 | 311 |
|
312 | 312 | 在了解了这些虚拟地址空间预设的情况下,进一步来考虑其他进程的内存布局。本次实验中,由于还没有“用户进程”的概念,可以暂时先考虑的少一些,但是便于本次实验使用的解决方案。 |
313 | 313 |
|
@@ -656,7 +656,6 @@ pub extern "x86-interrupt" fn page_fault_handler( |
656 | 656 |
|
657 | 657 | 3. 中断的处理过程默认是不切换栈的,即在中断发生前的栈上继续处理中断过程,为什么在处理**缺页异常和时钟中断**时需要切换栈?如果不为它们切换栈会分别带来哪些问题?请假设具体的场景、或通过实际尝试进行回答。 |
658 | 658 |
|
659 | | - |
660 | 659 | ??? question "可选思考题(提高)" |
661 | 660 |
|
662 | 661 | 1. 结合本实验中的线程调度,比较以下两种策略: |
|
0 commit comments