【操作系统原理】进程间通信之管道


🎉博主首页: 有趣的中国人

🎉专栏首页: 操作系统原理

🎉其它专栏: C++初阶 | C++进阶 | 初阶数据结构


文章目录

  • 【操作系统原理】进程间通信:管道(pipe/FIFO)
    • [1. 为什么需要进程间通信(IPC)](#1. 为什么需要进程间通信(IPC))
    • [2. 进程为什么不能直接"互相读写内存"](#2. 进程为什么不能直接“互相读写内存”)
    • [3. IPC 方式总览](#3. IPC 方式总览)
      • [3.1 本地通信(同一台机器)](#3.1 本地通信(同一台机器))
      • [3.2 网络通信(跨机器)](#3.2 网络通信(跨机器))
    • [4. 匿名管道 pipe:是什么](#4. 匿名管道 pipe:是什么)
      • [4.1 pipe 的核心模型](#4.1 pipe 的核心模型)
      • [4.2 重要限制](#4.2 重要限制)
    • [5. 管道的 4 种关键情形(面试高频)](#5. 管道的 4 种关键情形(面试高频))
      • [5.1 管道为空 + 写端存在](#5.1 管道为空 + 写端存在)
      • [5.2 管道写满 + 读端存在](#5.2 管道写满 + 读端存在)
      • [5.3 写端全部关闭(read 读到 EOF)](#5.3 写端全部关闭(read 读到 EOF))
      • [5.4 读端全部关闭(Broken Pipe / SIGPIPE)](#5.4 读端全部关闭(Broken Pipe / SIGPIPE))
    • [6. 管道的 5 个重要特征(理解到内核视角)](#6. 管道的 5 个重要特征(理解到内核视角))
      • [6.1 只能在亲缘进程间使用(匿名 pipe)](#6.1 只能在亲缘进程间使用(匿名 pipe))
      • [6.2 内部自带同步机制(顺序性)](#6.2 内部自带同步机制(顺序性))
      • [6.3 生命周期随进程(匿名 pipe 的"匿名")](#6.3 生命周期随进程(匿名 pipe 的“匿名”))
      • [6.4 面向字节流:消息边界会丢失](#6.4 面向字节流:消息边界会丢失)
      • [6.5 半双工模型(特殊)](#6.5 半双工模型(特殊))
    • [7. 命名管道 FIFO:解决"无亲缘也要通信"](#7. 命名管道 FIFO:解决“无亲缘也要通信”)
    • [8. 管道在工程里的经典用法:进程池(Master-Worker)](#8. 管道在工程里的经典用法:进程池(Master-Worker))
      • [8.1 进程池做什么](#8.1 进程池做什么)
      • [8.2 常见结构](#8.2 常见结构)
      • [8.3 最容易踩的坑](#8.3 最容易踩的坑)
    • [9. pipe / FIFO / socket 怎么选(快速决策)](#9. pipe / FIFO / socket 怎么选(快速决策))
    • [10. 小结](#10. 小结)

【操作系统原理】进程间通信:管道(pipe/FIFO)

1. 为什么需要进程间通信(IPC)

进程是"资源分配的基本单位",各自有独立的虚拟地址空间,默认互不干扰。

但真实系统里经常需要:

  • 多进程协作完成同一件事(流水线、进程池、服务拆分)
  • 数据共享与传递(任务、日志、控制指令、结果)
  • 提高吞吐与响应(并行处理)

结论:进程需要协同 → 必须通信


2. 进程为什么不能直接"互相读写内存"

因为这会破坏隔离性与安全性,成本也非常高。

系统的折中方案是:

让不同进程去访问同一份 OS 管理的"共享资源"

例如:内核缓冲区、共享内存段、消息队列对象、文件对象......

也就是:IPC 的核心不是"直接互访内存",而是"借助 OS 提供的通信媒介"。


3. IPC 方式总览

从常见使用场景看,大致分为两类:

3.1 本地通信(同一台机器)

  • 匿名管道(pipe)
  • 命名管道(FIFO)
  • System V IPC:消息队列 / 共享内存 / 信号量
  • Unix Domain Socket(本地 socket)

3.2 网络通信(跨机器)

  • TCP/UDP socket(走协议栈、可跨主机)

4. 匿名管道 pipe:是什么

匿名管道是最经典的本地 IPC。

4.1 pipe 的核心模型

  • pipe 由内核维护一段缓冲区(常见实现为环形队列)
  • 通过两个文件描述符访问:
    • 读端 fd:从缓冲区取数据
    • 写端 fd:向缓冲区写数据

4.2 重要限制

  • 只能用于"有血缘关系"的进程(通常是 fork 出来的父子进程)
  • 典型场景:父进程写、子进程读(或反过来)
  • 管道天然偏向"单向通信"(要双向需要两根管道)

5. 管道的 4 种关键情形(面试高频)

下面所有行为都可以用一句话记住:
空则读等,满则写等;写端全关读到 0;读端全关写会炸。

5.1 管道为空 + 写端存在

  • 读进程 read:阻塞等待
  • 这就是典型的"生产者-消费者"

5.2 管道写满 + 读端存在

  • 写进程 write:阻塞等待
  • 直到读端读走部分数据腾出空间

5.3 写端全部关闭(read 读到 EOF)

  • 当所有写端 fd 都关闭后:
    • 读端 read 会返回 0(EOF)
  • 这也是为什么:必须 close 不用的写端
    否则读端永远不会得到"结束"信号,可能一直阻塞。

5.4 读端全部关闭(Broken Pipe / SIGPIPE)

  • 当所有读端 fd 都关闭后:
    • 写端 write 会触发 Broken Pipe
    • 默认会收到 SIGPIPE(很多程序因此直接被终止)
  • 工程上通常会:
    • 忽略/捕捉 SIGPIPE
    • 或者对 write 的返回值进行错误处理(EPIPE)

6. 管道的 5 个重要特征(理解到内核视角)

6.1 只能在亲缘进程间使用(匿名 pipe)

因为 pipe 的 fd 是通过 fork 继承过去的。

6.2 内部自带同步机制(顺序性)

  • 同一根 pipe 上的数据是"字节流"顺序进入、顺序读出
  • 多写者场景下,内核会保证一定的原子性(与 PIPE_BUF 有关)

6.3 生命周期随进程(匿名 pipe 的"匿名")

  • pipe 本身没有文件名
  • 当进程退出、fd 全部关闭后,内核对象就会被回收

6.4 面向字节流:消息边界会丢失

  • 写入两次 ≠ 读两次(读到的数据可能粘在一起,也可能被拆开)
  • 所以工程上必须做"应用层协议":
    • 定长包
    • 分隔符
    • length + payload(最常见)

6.5 半双工模型(特殊)

一根 pipe 更天然的使用方式是"单向",像对讲机:

同一时刻更适合一边说一边听的单向流动。


7. 命名管道 FIFO:解决"无亲缘也要通信"

匿名 pipe 只能亲缘进程用,FIFO 用"文件名"把管道暴露出来:

  • FIFO 在文件系统里有一个名字(路径)
  • 无亲缘关系的进程也能通过这个路径打开同一条管道进行通信
  • 依然是:内核缓冲区 + 读写 fd(本质不变)

适用:同机上的两个独立程序(例如:日志采集器 ↔ 业务进程)。


8. 管道在工程里的经典用法:进程池(Master-Worker)

8.1 进程池做什么

  • Master:负责接收任务、分发任务、负载均衡
  • Worker:负责执行任务、返回结果(可选)

8.2 常见结构

  • Master 与每个 Worker 建立一条(或两条)管道
  • Master 端只保留写端,Worker 端只保留读端(其余全 close)
  • 分发策略:
    • 轮询(round-robin)
    • 最短队列(按繁忙度)
    • 哈希分桶(同类任务固定 worker)

8.3 最容易踩的坑

  • 忘记关闭无用端 → read 永远不返回 0 / write 触发 SIGPIPE 行为不清晰
  • 不做消息边界协议 → "粘包/拆包"导致任务解析错乱
  • 不处理 worker 退出 → master 写入触发 broken pipe

9. pipe / FIFO / socket 怎么选(快速决策)

  • 只在本机、亲缘进程:pipe(简单直接)
  • 本机、无亲缘:FIFO 或 Unix Domain Socket
  • 跨机器:TCP/UDP socket
  • 大块数据共享、追求极致性能:共享内存 + 信号量(或 futex 等)

10. 小结

  • IPC 的本质:借助 OS 提供的共享媒介
  • pipe/FIFO:内核缓冲区 + fd 读写 + 阻塞语义
  • 面试 4 情形必须背到"条件反射"
  • 工程落地一定要做:关闭无用端 + 应用层协议 + 异常处理
相关推荐
神的孩子都在歌唱1 小时前
eNSP 中使用 NAT 地址池实现内网出网转换
网络
zore_c1 小时前
【数据结构】队列——超详解!!!(包含队列的实现)
c语言·网络·数据结构·c++·笔记·算法·链表
可爱又迷人的反派角色“yang”4 小时前
ansible剧本编写(三)
linux·网络·云计算·ansible
m0_738120724 小时前
应急响应——知攻善防Web-3靶机详细教程
服务器·前端·网络·安全·web安全·php
橘子真甜~10 小时前
C/C++ Linux网络编程15 - 网络层IP协议
linux·网络·c++·网络协议·tcp/ip·计算机网络·网络层
Allen正心正念202511 小时前
网络编程与通讯协议综合解析
网络
bing_feilong11 小时前
ubuntu中的WIFI与自身热点切换
网络
CodeByV11 小时前
【网络】UDP 协议深度解析:从五元组标识到缓冲区
网络·网络协议·udp
虹科网络安全12 小时前
艾体宝洞察 | 利用“隐形字符”的钓鱼邮件:传统防御为何失效,AI安全意识培训如何补上最后一道防线
运维·网络·安全