进程的描述与控制
2026/1/30大约 4 分钟
第3章 进程的描述与控制
进程与线程的区别是什么?
- 进程是资源分配的最小单位,拥有独立内存
- 线程是 CPU 调度的最小单位,共享进程内存
- 进程切换开销大,线程切换开销小
- 线程共享内存需要同步控制
为什么线程切换比进程切换快?
- 不需要切换页表和文件描述符等重资源
- 线程共享进程地址空间,只需切换寄存器等少量状态
- 进程切换涉及更多内核数据结构恢复
进程切换为什么比线程更消耗资源?
进程切换时需要保存和恢复更多的上下文信息:
地址空间切换:
- 进程拥有独立的虚拟地址空间,切换时需要刷新TLB(转换后备缓冲区)
- 重新加载页表,获取新的地址空间
- 线程共享同一地址空间,无需此操作
上下文保存与恢复:
- 进程上下文包含完整的CPU状态(寄存器、程序计数器)
- 还需要保存内存管理信息、文件描述符表等
- 线程上下文仅包含CPU状态和少量私有数据
内核数据结构更新:
- 进程切换涉及调度器、内存管理等多个内核子系统
- 需要更新进程状态、调度队列等
- 线程切换涉及的内核数据结构更少
进程和线程的区别是什么?
| 特性 | 进程 | 线程 |
|---|---|---|
| 资源分配 | 独立的内存空间,资源分配单位 | 共享进程资源,CPU调度单位 |
| 切换开销 | 大,需要切换地址空间和内核数据结构 | 小,仅需切换CPU状态 |
| 崩溃影响 | 一个进程崩溃不影响其他进程 | 线程崩溃会影响同进程所有线程 |
| 通信方式 | IPC(管道、消息队列、共享内存等) | 共享内存、锁、条件变量等 |
| 创建速度 | 慢,需要分配资源 | 快,复用进程资源 |
为什么要有线程?
- 线程更轻量,创建/上下文切换成本低
- 更适合 并发、IO 密集、CPU 多核利用
- 提高程序响应性(UI 主线程 / 工作线程)
什么是僵尸进程与孤儿进程?
- 僵尸进程:子进程结束但父未 wait → 占用进程表项
- 孤儿进程:父进程结束但子还在 → 被 init 接管
- 僵尸进程过多会耗尽 PID 资源
进程间通信(IPC)方式有哪些?用在哪里?
进程间通信是指不同进程之间交换数据、共享资源的机制,主要包括以下几种方式:
1. 管道(Pipe)
匿名管道:
- 半双工通信,数据只能单向流动
- 只能在具有亲缘关系的进程(如父子进程)间使用
- 管道内容存放在内存中,无外部名称
- 示例:
ls | grep "test"命令中的管道
命名管道(FIFO):
- 具有文件路径名,存在于文件系统中
- 支持无亲缘关系的进程间通信
- 严格遵循先进先出(FIFO)原则
- 示例:不同进程通过同一命名管道交换数据
2. 消息队列
- 存储结构化消息的链表,存在于内核中
- 每个消息有类型标识,接收方可以按类型读取
- 消息大小有上限,队列总大小也有上限
- 示例:进程间传递结构化数据,如日志、命令等
3. 共享内存
- 最快的 IPC 方式,直接访问物理内存
- 进程间共享同一块内存区域
- 需要同步机制(如信号量)防止数据竞争
- 示例:高性能应用中的进程间数据共享
4. 信号量
- 用于进程间同步和互斥
- 本质是一个计数器,记录可用资源数量
- 支持 P 操作(申请资源)和 V 操作(释放资源)
- 示例:控制多个进程对共享资源的访问
5. 信号
- 用于进程间事件通知
- 异步通信机制,进程可以忽略或处理信号
- 常见信号:SIGINT(Ctrl+C)、SIGHUP(终端关闭)、SIGQUIT(Ctrl+\)
- 示例:通知进程终止、重启等
6. Socket
- 支持跨机器通信,是网络通信的基础
- 可以用于同一机器上的进程通信
- 支持 TCP(可靠)和 UDP(不可靠)协议
- 示例:微服务间通信、网络应用
线程安全如何保证?
- 互斥锁(synchronized/Lock)
- CAS + 原子类
- 读写锁
- ThreadLocal
- 不可变对象(final)