操作系统学习笔记——进程间通信方式详解及优缺点对比,僵尸进程,孤儿进程,守护进程
进程间通信方式详解及优缺点对比
- 一、常见进程间通信方式及解释
- 1. 管道(Pipe)
- ✅ 定义:
- ✅ 特点:
- ✅ 优点:
- ❌ 缺点:
- 2. 命名管道(Named Pipe / FIFO)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 3. 流管道(s_pipe)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 4. 消息队列(Message Queue)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 5. 信号量(Semaphore)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 6. 信号(Signal)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 7. 共享内存(Shared Memory)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 8. 套接字(Socket)
- ✅ 定义:
- ✅ 优点:
- ❌ 缺点:
- 二、通信方式对比表(总结)
- 三、进程间通信方式怎么选?
- 四、线程间同步机制有哪些?
- 1. 临界区(Critical Section)
- 2. 互斥量(Mutex)
- 3. 信号量(Semaphore)
- 4. 事件(Event)
- 用户线程(User Thread)是啥?
- 特点:
- 内核线程(Kernel Thread)是啥?
- 特点:
- 用户线程和内核线程的区别
- 两者优缺点总结
- 用户线程的优点:
- 用户线程的缺点:
- 内核线程的优点:
- 内核线程的缺点:
- 什么是僵尸进程、孤儿进程、守护进程?
- 僵尸进程(Zombie Process)
- 如何避免僵尸进程?
- 孤儿进程(Orphan Process)
- 守护进程(Daemon)
- 僵尸进程、孤儿进程、守护进程的对比
一、常见进程间通信方式及解释
1. 管道(Pipe)
✅ 定义:
管道是最基本的进程间通信方式,允许一个进程将数据传输给另一个进程。
✅ 特点:
- 半双工通信:数据只能单向传输;
- 有亲缘限制:只能用于父子进程之间。
✅ 优点:
- 简单易用,适合基础场景。
❌ 缺点:
- 不能用于无关进程;
- 传输方向单一;
- 通信缓冲区有限,速度较慢。
2. 命名管道(Named Pipe / FIFO)
✅ 定义:
命名管道为普通管道加了“名字”,因此可以让无亲缘关系的进程通信。
✅ 优点:
- 可用于无亲缘关系的进程间通信;
- 仍然是管道模型,使用简单。
❌ 缺点:
- 通信效率仍不高;
- 适合小量、频繁的数据传输。
3. 流管道(s_pipe)
✅ 定义:
流管道是一种全双工管道,突破了传统管道“只能单向传输”的限制。
✅ 优点:
- 支持双向通信,更灵活。
❌ 缺点:
- 实现复杂度稍高;
- 使用范围仍有限。
4. 消息队列(Message Queue)
✅ 定义:
消息队列是一个内核维护的消息链表,进程可以写入和读取消息,彼此通信。
✅ 优点:
- 支持格式化数据;
- 通信无需同步机制;
- 可用于任意进程之间。
❌ 缺点:
- 消息长度和数量有限;
- 复制数据时消耗 CPU;
- 不适合大数据或高频传输。
5. 信号量(Semaphore)
✅ 定义:
信号量不是用来传数据,而是用来协调多个进程/线程对共享资源的访问。
✅ 优点:
- 常用于同步控制;
- 多进程/多线程环境下非常实用。
❌ 缺点:
- 不适合传递复杂数据;
- 实现需要理解同步机制。
6. 信号(Signal)
✅ 定义:
信号是操作系统中用来通知进程发生某些事件的一种机制。
✅ 优点:
- 通知机制灵活;
- 能跨进程、跨线程使用。
❌ 缺点:
- 通信内容简单,仅是“通知”;
- 响应处理较复杂。
7. 共享内存(Shared Memory)
✅ 定义:
多个进程通过访问同一块内存区域来实现数据交换。
✅ 优点:
- 通信速度极快,无须复制数据;
- 适合大量数据、高频传输;
- 可被多个进程共享。
❌ 缺点:
- 需要加锁机制(如信号量)防止竞争;
- 使用稍复杂,需要同步控制。
8. 套接字(Socket)
✅ 定义:
套接字是一种通用通信机制,甚至可以用于不同主机之间的数据传输(例如分布式系统)。
✅ 优点:
- 支持网络通信;
- 可用于远程或不同机器的进程通信;
- 支持 TCP/UDP 协议,灵活强大。
❌ 缺点:
- 实现相对复杂;
- 通信效率不如共享内存。
二、通信方式对比表(总结)
通信方式 | 是否支持无亲缘进程 | 是否支持网络通信 | 是否双向 | 通信速度 | 是否传数据 | 是否同步控制 |
---|---|---|---|---|---|---|
管道 | 否 | 否 | 否 | 慢 | 是 | 否 |
命名管道 | 是 | 否 | 否 | 慢 | 是 | 否 |
流管道 | 否(通常) | 否 | 是 | 一般 | 是 | 否 |
消息队列 | 是 | 否 | 是 | 一般 | 是 | 是 |
信号量 | 是 | 否 | 否 | 快 | 否 | 是 |
信号 | 是 | 否 | 否 | 一般 | 否(通知) | 是 |
共享内存 | 是 | 否 | 是 | 快 | 是 | 是 |
套接字 | 是 | 是 | 是 | 一般 | 是 | 需控制 |
三、进程间通信方式怎么选?
- 频繁、小量通信 → 用
PIPE
或FIFO
- 大量数据、高频访问 →
共享内存 + 信号量
- 多机器/分布式系统通信 →
Socket
- 仅做同步控制,不传数据 →
信号量
或信号
四、线程间同步机制有哪些?
除了进程之间的通信,线程之间也常常需要同步互斥控制,避免资源冲突。最基础的4种机制如下:
1. 临界区(Critical Section)
- 适用于保护同一进程内的共享资源;
- 快速、适合控制数据访问;
- 在任何时刻只能有一个线程进入。
2. 互斥量(Mutex)
- 类似临界区,但可用于跨进程通信;
- 实现对共享资源的互斥访问;
- 拥有互斥量的线程才能访问资源。
3. 信号量(Semaphore)
- 可允许多个线程同时访问资源;
- 常用于有限资源控制(如连接池、任务队列等);
- 支持访问数的限制。
4. 事件(Event)
- 用于线程间通知机制;
- 可用于唤醒其他线程执行某些任务;
- 适合处理异步任务依赖。
好的,下面我会以面向小白、通俗易懂的方式,将“内核线程 vs 用户线程 + 僵尸进程、孤儿进程、守护进程”整理为一篇结构清晰、内容详实、适合 CSDN 发布的文档。文中将包含大量示意、比喻、易懂的讲解,帮助新手快速掌握知识。
用户线程(User Thread)是啥?
用户线程,顾名思义,是运行在用户空间的线程。它是通过 线程库(如 pthread、Java 的线程类等)在用户程序中创建和管理的。
特点:
- 不需要操作系统内核支持,全部在线程库中搞定。
- 切换速度快:线程之间切换不需要陷入内核(省去了用户态和内核态的切换)。
- 缺点是:一荣俱荣一损俱损。如果一个线程被阻塞(比如 I/O),整个进程都会挂起。
想象你和朋友一起排队打游戏(排队系统是用户线程库),你排到一半突然去上厕所(阻塞),那后面的人也只能等你回来——因为只有一个游戏机位(进程只在一个 CPU 上运行)。
内核线程(Kernel Thread)是啥?
内核线程是真正由 操作系统内核管理的线程,系统可以感知到它们的存在。线程的调度、切换由操作系统来控制。
特点:
- 线程调度由内核完成,调度精细且高效。
- 可以在多核处理器上实现真正的并行。
- 某个线程被阻塞,不影响同进程的其他线程。
继续刚才的比喻:
- 内核线程就像是一个游戏厅(多核 CPU)里的多个游戏机(内核线程),你和朋友可以分开玩。你去上厕所,朋友还可以继续玩。
用户线程和内核线程的区别
项目 | 用户线程(User Thread) | 内核线程(Kernel Thread) |
---|---|---|
是否内核可见 | 否 | 是 |
创建与销毁 | 用户级线程库控制 | 操作系统控制 |
切换代价 | 小,无需内核态切换 | 大,涉及内核态切换 |
系统调用影响 | 可能阻塞整个进程 | 只阻塞当前线程 |
多处理器支持 | 不好,不能并行运行 | 支持真正并行 |
两者优缺点总结
用户线程的优点:
- 开销小:创建、销毁快,切换快。
- 灵活:可以自定义调度策略。
- 可以在不支持多线程的系统上实现。
用户线程的缺点:
- 一个线程阻塞,全体挂起。
- 无法利用多核 CPU 实现并行。
内核线程的优点:
- 真正并发:支持多核并行。
- 阻塞隔离:一个线程阻塞不影响其他线程。
内核线程的缺点:
- 开销大:线程调度需要系统干预。
- 创建销毁慢,上下文切换成本高。
什么是僵尸进程、孤儿进程、守护进程?
僵尸进程(Zombie Process)
子进程退出,但父进程没调用
wait()
回收它的状态信息,子进程就变成了僵尸。
它已经“死了”,但进程表里还留着尸体(资源信息没释放,PID 被占用)。
危害:
- 僵尸进程多了,PID 会耗尽,系统无法创建新进程!
如何避免僵尸进程?
- 父进程要记得调用
wait()
或waitpid()
。 - 如果父进程没写好,可以杀掉父进程,让僵尸进程变成孤儿进程被 init(PID=1)接管并回收。
孤儿进程(Orphan Process)
子进程还活着,但父进程已经挂了。
此时,操作系统会让 init
(进程号 1)来接管这些孤儿,并负责善后。
守护进程(Daemon)
守护进程是 一直在后台默默运行 的进程,比如 crond
定时任务、nginx
、mysqld
等等。
它通常在启动时就脱离了终端、脱离父进程,由 init
进程接管。
特点:
- 在系统后台运行
- 不和终端绑定
- 通常被设置为系统服务
僵尸进程、孤儿进程、守护进程的对比
类型 | 状态 | 被谁管理 | 是否会影响系统资源 |
---|---|---|---|
僵尸进程 | 已退出但未回收 | 父进程未处理 | 会占用 PID,长期不回收会出问题 |
孤儿进程 | 父进程先退出 | init 进程接管 | 会被自动回收 |
守护进程 | 主动脱离父进程 | init 进程接管 | 通常作为后台服务 |