主题
18 · 线程、调度与上下文切换
目标:区分线程与进程,建立「就绪 / 运行 / 时间片」直觉,并用命令看见线程。
前置:17 · 进程;命令行对照 05。
1. 环境前提
bash
mkdir -p ~/lab/os
# htop 若未装:sudo apt install -y htop1
2
2
2. 概念框(轻量课本)
| 词 | 一句话 |
|---|---|
| 线程 | 进程内的执行流;同进程线程共享地址空间与大部分资源,各有栈与寄存器 |
| 调度 | 内核决定下一瞬间哪个线程占用 CPU |
| 就绪 / 运行 / 阻塞 | 等 CPU / 正在跑 / 等 I/O 或锁等 |
| 时间片 | 一个线程连续占用 CPU 的一小段时间;到期或阻塞就切换 |
| 上下文切换 | 保存当前寄存器等状态,装入另一个线程的状态(有开销) |
Linux 实现细节(知道即可):历史上「轻量进程」;用户态常说 pthread,内核调度的是 task。
text
进程 A
├─ 线程 A1 ──┐
└─ 线程 A2 ──┼── 共享同一地址空间
进程 B(单线程)─┘── 另一片地址空间
▲
调度器轮流给 CPU1
2
3
4
5
6
2
3
4
5
6
3. 动手:看见线程
bash
# 列出某进程的线程(LWP = 轻量进程号,常等于线程 id)
ps -eLf | head -n 5
ps -L -p $$
# /proc 里 Threads 字段
grep -E '^(Name|Threads|Pid)' /proc/$$/status
ls /proc/$$/task1
2
3
4
5
6
7
2
3
4
5
6
7
找一个多线程样本(Nginx worker 或你自己的服务):
bash
pgrep -a nginx | head
# 换成实际 PID
PID=$(pgrep -n nginx || true)
if [[ -n "${PID}" ]]; then
ps -L -p "$PID"
grep Threads /proc/"$PID"/status
fi1
2
3
4
5
6
7
2
3
4
5
6
7
在 htop 中:H 切换是否显示线程(版本不同快捷键可能变;看界面帮助)。
对比心智:
| 多进程 | 多线程 | |
|---|---|---|
| 崩溃隔离 | 较好 | 一线程写坏内存可拖垮整进程 |
| 通信 | IPC / 网络 | 直接共享内存(要自己同步) |
| 运维可见 | 多个 PID | 常一个 PID + 多个 LWP |
本系列不写锁与死锁专章;写并发程序时再补。
4. 与命令行篇对照
| 05 / 运维动作 | OS 视角 |
|---|---|
| CPU 100% | 线程长时间处于 Running,或忙等 |
load average(uptime) | 就绪队列偏长的经验指标 |
| 卡死但 CPU 低 | 更可能阻塞在 I/O / 锁,不是「没调度」 |
5. 动手清单
- [ ]
ps -L -p $$看清当前 shell 的线程 - [ ] 对 nginx(或任意服务)看
Threads与task/ - [ ] 用自己的话区分:进程 vs 线程;就绪 vs 阻塞
- [ ] (可选)
uptime看一眼 load,对照机器核数
6. 常见翻车
| 翻车 | 处理 |
|---|---|
ps -L 空或只有一行 | 该程序就是单线程,正常 |
| 以为「核数 = 进程数上限」 | 进程/线程可远多于核数,靠时间片轮转 |
| 把 load=核数当成「必须等于」 | load 是滑动平均,解读要结合场景 |
7. 官方 / 延伸
man ps(-L、-eLf)man 7 pthreads(用户态线程 API 概览)- CFS 调度器文档(选读)
下一篇:虚拟内存、RSS 与 OOM。
