Update 计算机操作系统 - 进程管理.md

重新绘制配图,补充上下文切换。
This commit is contained in:
CyC2018
2026-10-26 22:04:16 +08:00
parent e944d6a385
commit f77a380a04
9 changed files with 30 additions and 9 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

+30 -9
View File
@@ -6,6 +6,7 @@
* [2. 线程](#2-线程)
* [3. 区别](#3-区别)
* [4. 协程](#4-协程)
* [5. 上下文切换](#5-上下文切换)
* [进程状态的切换](#进程状态的切换)
* [进程调度算法](#进程调度算法)
* [1. 批处理系统](#1-批处理系统)
@@ -26,6 +27,7 @@
* [4. 信号量](#4-信号量)
* [5. 共享存储](#5-共享存储)
* [6. 套接字](#6-套接字)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
@@ -37,9 +39,9 @@
进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。
下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。
下图显示了 4 个进程在一个 CPU 上并发地执行。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a6ac2b08-3861-4e85-baa8-382287bfee9f.png"/> </div><br>
<div align="center"> <img src="pics/process-concurrent.png" width="740px"/> </div><br>
### 2. 线程
@@ -49,7 +51,7 @@
QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/3cd630ea-017c-488d-ad1d-732b4efeddf5.png"/> </div><br>
<div align="center"> <img src="pics/process-threads.png" width="740px"/> </div><br>
### 3. 区别
@@ -81,9 +83,23 @@ QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 H
Java 21 正式引入的虚拟线程([JEP 444](https://openjdk.org/jeps/444))就是 JVM 实现的协程:虚拟线程由 JVM 调度到少量的平台线程上运行,执行阻塞 I/O 时从平台线程上卸载,让平台线程去执行其它虚拟线程。虚拟线程的创建成本很低,不需要用线程池复用,需要限制并发数时使用信号量。在 JDK 21 中,虚拟线程在 synchronized 块内阻塞时无法卸载,JDK 24 起([JEP 491](https://openjdk.org/jeps/491))基本消除了这个限制。
### 5. 上下文切换
上下文切换指的是 CPU 从执行一个线程改为执行另一个线程时,把当前线程的寄存器、程序计数器、栈指针等保存起来,再恢复另一个线程上次保存的值。以下情况会发生上下文切换:
- 时间片用完,被调度程序换下;
- 线程主动阻塞,例如等待 I/O、等待锁、调用 sleep();
- 更高优先级的线程进入就绪状态。
需要注意的是,系统调用只是从用户态进入内核态,执行完后通常回到同一个线程,不一定发生上下文切换。
同一进程中的线程切换不需要换地址空间;切换到另一个进程时还要切换页表,TLB 和 CPU 缓存中原来的地址映射和数据对新进程没有用,要重新加载,这部分间接开销通常比保存寄存器更大。
在 Linux 容器中用 taskset 把两个执行流固定在同一个 CPU 上,通过两根管道来回传 1 个字节,让它们交替运行:两个线程之间、两个进程之间每次切换都约 1.1 微秒(包含一次 read 或 write 系统调用)。数据量很小时两者几乎没有差别,进程切换的额外开销主要在工作集较大时体现出来。线程过多、频繁阻塞时,CPU 会把相当一部分时间花在切换上,可以用 vmstat 的 cs 列或 pidstat -w 观察每秒的切换次数。
## 进程状态的切换
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ProcessState.png" width="500"/> </div><br>
<div align="center"> <img src="pics/process-states.png" width="720px"/> </div><br>
- 就绪状态(ready):等待被调度
- 运行状态(running)
@@ -131,7 +147,7 @@ Java 21 正式引入的虚拟线程([JEP 444](https://openjdk.org/jeps/444))
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
- 而如果时间片过长,那么实时性就不能得到保证。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8c662999-c16c-481c-9f40-1fdba5bc9167.png"/> </div><br>
<div align="center"> <img src="pics/process-rr.png" width="740px"/> </div><br>
**2.2 优先级调度**
@@ -149,7 +165,7 @@ Java 21 正式引入的虚拟线程([JEP 444](https://openjdk.org/jeps/444))
可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/042cf928-3c8e-4815-ae9c-f2780202c68f.png"/> </div><br>
<div align="center"> <img src="pics/process-mlfq.png" width="740px"/> </div><br>
### 3. 实时系统
@@ -323,7 +339,7 @@ end;
### 1. 哲学家进餐问题
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a9077f06-7584-4f2b-8c20-3a8e46928820.jpg"/> </div><br>
<div align="center"> <img src="pics/philosophers.png" width="720px"/> </div><br>
五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
@@ -568,7 +584,7 @@ int pipe(int fd[2]);
- 只支持半双工通信(单向交替传输);
- 只能在父子进程或者兄弟进程中使用。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/53cd9ade-b0a6-4399-b4de-7f1fbd06cdfb.png"/> </div><br>
<div align="center"> <img src="pics/pipe.png" width="740px"/> </div><br>
### 2. FIFO
@@ -582,7 +598,7 @@ int mkfifoat(int fd, const char *path, mode_t mode);
FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2ac50b81-d92a-4401-b9ec-f2113ecc3076.png"/> </div><br>
<div align="center"> <img src="pics/fifo.png" width="720px"/> </div><br>
### 3. 消息队列
@@ -607,3 +623,8 @@ FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户
### 6. 套接字
与其它通信机制不同的是,它可用于不同机器间的进程通信。
## 参考资料
- Tanenbaum A S, Bos H. Modern Operating Systems [M]. Pearson, 2014.
- [pipe(7) — Linux manual page](https://man7.org/linux/man-pages/man7/pipe.7.html)