1305 字
3 分钟
OS笔记(五):线程
OS笔记(五):线程
本文是操作系统笔记系列的第五篇,详细讲解线程的概念、用户级线程与内核级线程的区别、多线程模型,以及Linux中的线程管理。
📚 目录
一、线程的概念
1.1 什么是线程?
线程(Thread)可以理解为轻量级进程。它是:
- CPU执行的基本单位
- 程序执行流的最小单位
1.2 为什么引入线程?
| 问题 | 解决方案 |
|---|---|
| 进程切换开销大 | 线程切换开销小 |
| 进程并发度有限 | 同一进程的线程可以并发 |
| 进程间通信复杂 | 线程间可以直接共享数据 |
1.3 进程 vs 线程
| 对比项 | 进程 | 线程 |
|---|---|---|
| 本质 | 资源分配的基本单位 | CPU执行的基本单位 |
| 资源 | 拥有独立的资源 | 几乎不拥有资源 |
| 切换开销 | 大(切换地址空间) | 小(共享地址空间) |
| 通信方式 | 需要IPC机制 | 直接读写共享变量 |
| 崩溃影响 | 不影响其他进程 | 可能导致整个进程崩溃 |
1.4 线程的属性
- 线程是处理机调度的单位
- 多CPU计算机中,各线程可占用不同的CPU
- 每个线程都有一个线程ID和TCB(线程控制块)
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的线程共享进程资源
- 同一线程的线程通信无需系统干预
- 同一进程的线程切换不会引起进程切换
- 不同进程的线程切换会引起进程切换
- 切换同进程内线程的开销很小
- 切换进程的开销很大
二、线程的实现方式
2.1 用户级线程(User-Level Thread)

| 特点 | 说明 |
|---|---|
| 管理者 | 应用程序(线程库) |
| 切换位置 | 用户态 |
| OS感知 | OS不知道线程存在 |
优点:
- 切换不需要切换到核心态,开销小、效率高
缺点:
- 一个线程阻塞会导致整个进程阻塞
- 无法利用多核CPU
2.2 内核级线程(Kernel-Level Thread)

| 特点 | 说明 |
|---|---|
| 管理者 | 操作系统内核 |
| 切换位置 | 核心态 |
| OS感知 | OS为每个线程建立TCB |
优点:
- 一个线程阻塞不影响其他线程
- 可以利用多核CPU
缺点:
- 切换需要切换到核心态,开销大
2.3 用户级 vs 内核级
| 对比 | 用户级线程 | 内核级线程 |
|---|---|---|
| 切换开销 | 小 | 大 |
| 并发能力 | 弱 | 强 |
| 多核利用 | 不能 | 能 |
| 阻塞影响 | 整个进程阻塞 | 仅当前线程阻塞 |
重点:操作系统只能看到内核级线程!
三、多线程模型
3.1 一对一模型
一个用户级线程对应一个内核级线程。

| 优点 | 缺点 |
|---|---|
| 并发能力强 | 线程管理成本高 |
3.2 多对一模型
多个用户级线程对应一个内核级线程。

| 优点 | 缺点 |
|---|---|
| 切换开销小 | 并发性不好 |
3.3 多对多模型
多个用户级线程对应多个内核级线程。

| 优点 | 特点 |
|---|---|
| 兼顾并发性和开销 | 折中方案 |
3.4 模型对比
| 模型 | 用户级:内核级 | 并发性 | 开销 |
|---|---|---|---|
| 一对一 | 1:1 | 最强 | 最大 |
| 多对一 | N:1 | 最弱 | 最小 |
| 多对多 | N | 较强 | 较小 |
四、线程的状态与控制
4.1 线程的状态
线程也有三种基本状态:

### 4.2 线程控制块(TCB)
TCB存储线程的信息:
| 信息 | 说明 ||------|------|| 线程ID | 唯一标识 || 程序计数器 | 下一条指令地址 || 寄存器值 | CPU寄存器状态 || 栈指针 | 线程栈的位置 || 线程状态 | 就绪/运行/阻塞 |

---
<a id="linux"></a>## 五、Linux实战:线程管理
### 5.1 Linux中的线程
Linux中线程被称为**轻量级进程**(LWP),使用 `clone()` 系统调用创建。
### 5.2 查看线程
```bash# 查看进程的线程ps -T -p <PID>
# 查看所有线程ps -eLf
# 使用top查看线程top -H -p <PID>
# 使用htop(更直观)htop -H5.3 创建线程(C语言)
cat > thread_demo.c << 'EOF'#include <stdio.h>#include <pthread.h>
void* thread_func(void* arg) { printf("线程 %ld 运行中\n", (long)arg); return NULL;}
int main() { pthread_t threads[3];
// 创建3个线程 for (long i = 0; i < 3; i++) { pthread_create(&threads[i], NULL, thread_func, (void*)i); }
// 等待线程结束 for (int i = 0; i < 3; i++) { pthread_join(threads[i], NULL); }
printf("所有线程执行完毕\n"); return 0;}EOF
gcc thread_demo.c -lpthread -o thread_demo./thread_demo5.4 创建线程(Python)
python3 << 'EOF'import threadingimport time
def worker(tid): print(f"线程 {tid} 开始") time.sleep(1) print(f"线程 {tid} 结束")
# 创建5个线程threads = []for i in range(5): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start()
# 等待所有线程完成for t in threads: t.join()
print("所有线程执行完毕")EOF5.5 线程同步
python3 << 'EOF'import threading
counter = 0lock = threading.Lock()
def increment(): global counter for _ in range(100000): with lock: counter += 1
# 创建10个线程并发修改共享变量threads = []for _ in range(10): t = threading.Thread(target=increment) threads.append(t) t.start()
for t in threads: t.join()
print(f"最终计数: {counter}") # 应该是1000000EOF5.6 线程vs进程性能对比
python3 << 'EOF'import threadingimport multiprocessingimport time
def task(): sum(range(1000000))
# 测试线程start = time.time()threads = [threading.Thread(target=task) for _ in range(4)]for t in threads: t.start()for t in threads: t.join()thread_time = time.time() - start
# 测试进程start = time.time()processes = [multiprocessing.Process(target=task) for _ in range(4)]for p in processes: p.start()for p in processes: p.join()process_time = time.time() - start
print(f"线程耗时: {thread_time:.3f}s")print(f"进程耗时: {process_time:.3f}s")EOF5.7 查看线程详细信息
# 查看线程栈信息cat /proc/<PID>/task/<TID>/stack
# 查看线程状态cat /proc/<PID>/task/<TID>/status
# 使用pstack查看线程栈pstack <PID>六、本章小结
核心概念
| 概念 | 要点 |
|---|---|
| 线程 | CPU执行的基本单位,轻量级进程 |
| 用户级线程 | 用户态切换,开销小,并发弱 |
| 内核级线程 | 核心态切换,开销大,并发强 |
| 一对一模型 | 并发强,开销大 |
| 多对一模型 | 并发弱,开销小 |
| 多对多模型 | 折中方案 |
线程实现方式对比
| 对比项 | 用户级线程 | 内核级线程 |
|---|---|---|
| 切换位置 | 用户态 | 核心态 |
| OS感知 | 否 | 是 |
| 切换开销 | 小 | 大 |
| 并发能力 | 弱 | 强 |
| 多核利用 | 不能 | 能 |
考研/期末常见考点
- 线程和进程的区别
- 用户级线程和内核级线程的区别
- 三种多线程模型的特点和对比
- OS只能看到内核级线程
- 线程切换和进程切换的开销对比
思考题
- 为什么说线程是”轻量级进程”?
- 用户级线程为什么不能利用多核CPU?
- 多对多模型是如何兼顾并发性和开销的?
上一篇:OS笔记(四):进程通信 下一篇:OS笔记(六):调度的概念、层次
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时
相关文章 智能推荐
1
OS笔记(一):进程与线程简介
操作系统 深入理解操作系统中进程与线程的概念、组成、特征,以及它们在Linux系统中的实际表现
2
OS笔记(三):进程控制
操作系统 深入理解操作系统中原语的概念、进程的创建/终止/阻塞/唤醒/切换机制,以及Linux中的进程管理实践
3
OS笔记(四):进程通信
操作系统 深入理解操作系统中进程间通信的三种方式:共享存储、消息传递、管道通信,以及Linux IPC实战
4
OS笔记(六):调度的概念、层次
操作系统 深入理解操作系统中调度的三个层次、七状态模型,以及Linux进程调度机制
5
OS笔记(二):进程的状态与转换
操作系统 深入理解操作系统中进程的五种状态、状态转换条件,以及在Linux中如何观察进程状态








