第 43 章 进程间通信概述 (IPC Overview)

      +

      核心结论

      • IPC 三大功能分类:communication(交换数据)、synchronization(协调动作)、signals(极少用作通信的同步机制)。所有 IPC 设施可分为「数据传输」(data-transfer)和「共享内存」两条主线。

      • 数据传输 vs 共享内存:数据传输(管道、FIFO、消息队列、套接字)需要内核往返(user→kernel→user);共享内存允许多进程映射同一页帧——速度极快但需用户态同步。

      • 数据子形态:byte stream(管道、FIFO、流套接字,无消息边界)和 message(SysV/POSIX 消息队列、数据报套接字,整条消息原子读)。伪终端 (PTY) 是特殊管道。

      • 同步三大设施:semaphores(二值/计数)、file locks(flock()/fcntl() record lock)、mutex+condvar(线程级,部分支持进程共享)。Linux 2.6.22+ 还提供 eventfd 用于 select/poll/epoll 同步。

      • IPC 选择维度:identifier(pathname/fd/IPC key/mqd_t),functionality(数据形态 + 持久性 + 网络能力),accessibility(permissions / related-process only),persistence(process/kernel/file-system),performance(应用 benchmark 决定)。

      • POSIX vs System V:POSIX 接口以 pathname + fd 为主(一致性更好);System V IPC 早已存在更易移植但设计有缺陷(无引用计数、不像 fd)。

      本章主旨

      本章是后续 6 章 IPC 的导论:先理清分类——communication / synchronization / signals;communication 又分 data-transfer 与 shared memory;data-transfer 又分 byte stream 与 message。读者应建立 IPC 「选型表」:(1) 通信是否需要跨越主机?(socket 否则管道/FIFO);(2) 数据形态?消息 or 字节流;(3) 持久性?kernel-persistent 让进程退出后仍存在;(4) 需要 select/poll/epoll?(file descriptor-based 才行);(5) 同步需求?semaphore/file lock。读完本章应该能初步决定工具选型。

      一、核心概念

      本章围绕 6 个核心概念展开:从 IPC 分类树、数据传输与共享内存、byte stream vs message、同步设施、IPC 选择维度、POSIX vs SysV 比较。

      概念 定义 + 重要性 实现提示

      IPC 三大分类

      communication(数据交换)、synchronization(动作协调)、signals(也可作同步)——所有 IPC 设施归到此三类;统称 Inter-Process Communication

      §43.1;选型时先看目的是「交换数据」还是「协调动作」

      数据传输 vs 共享内存

      数据传输需要 user→kernel→user 两次拷贝(pipe 写入+读出);共享内存把同一物理页映射到两个进程,「无内核介入」——最快但要自己同步

      §43.2;共享内存系统调用有 SysV (shmget/shmat)、POSIX (shm_open/mmap)、mmap file/anon

      byte stream vs message

      byte stream(管道、FIFO、流套接字)无消息边界——read N 字节可来自任一次 write;message(消息队列、数据报套接字)整条原子读

      §43.2;传离散消息优先 message;字节流协议(HTTP、protobuf over pipe)则用 byte stream

      同步设施选择

      semaphores(SysV/POSIX)通用;file locks(fcntl record lock)专门协调文件访问;mutex+condvar 线程共享;eventfd 通知而非锁

      §43.3;fcntl() lock 有死锁检测、随进程终止自动释放;System V sem 没有所有权死锁检测

      IPC 选择维度

      5 个维度:name/handle(path/key/fd)、functionality(byte stream vs message、持久性、网络可达)、accessibility(权限/相关进程)、persistence(process/kernel/filesystem)、performance(实测)

      §43.4;Table 43-1 + Table 43-2 一站对照

      POSIX vs SysV IPC 比较

      SysV:更早,移植到所有 UNIX;但无 fd 引用计数、IPC key 设计不一致;POSIX:pathname + fd 接口更现代、Linux 2.6 全支持

      §43.4;新代码优先 POSIX;老 SysV 代码仍需维护

      二、详细笔记

      43.1 IPC 分类法

      What:UNIX IPC 设施分成 3 大类(communication/synchronization/signals);细分为 12 项(图 43-1)。

      Why:选 IPC 时先回答「我要干什么」(换数据?同步?)。

      How

      1. 通信设施:管道、FIFO、消息队列(SysV/POSIX)、共享内存(SysV/POSIX/mmap)、套接字(UNIX/INET domain)。

      2. 同步设施:semaphores(SysV/POSIX)、file locks(flock()/fcntl())、mutex+condvar、eventfd(2.6.22+)。

      3. signals:传统上不算 IPC,但实时信号带数据(sigqueue()),可用作 limited 通信。

      When:写新 IPC 代码先查 §43.1 图 43-1 决定大类。

      43.2 数据传输 vs 共享内存

      What:通信目的 → 数据传输 vs 共享内存的根本选择。

      Why:共享内存快但需自己同步;数据传输自动同步但有 2 次拷贝。

      How——比较表(来自 §43.2):

      属性 数据传输 共享内存

      内核介入

      每次 write/read 都过内核

      仅 shmget/mmap 一次,之后无内核

      数据流向

      单向 / 双向

      多进程可读写同一段

      读语义

      破坏性(读走后没了)

      非破坏性

      同步

      自动(empty 时阻塞)

      需用户态(sem/cond)

      速度

      慢(2 次拷贝 + syscall)

      快(无拷贝)

      持久性

      process(fd 关就丢)

      kernel(SysV/POSIX)或 file-system(mmap file)

      When:高频大块传输→共享内存;小消息/控制流→管道或 FIFO/消息队列。

      43.3 同步设施

      What:semaphores、file locks、mutex/condvar、eventfd。

      Why:不协调多进程访问→数据竞争→崩溃或损坏。

      How

      1. semaphores:内核维护整数;P 减、值 ≥0;V 加;为 0 时阻塞。SysV/POSIX 两套,API 类似。

      2. file locksflock(fd, LOCK_SH|LOCK_EX|LOCK_UN)——全文件锁,简单;fcntl(fd, F_SETLK, …​)——记录锁,灵活。

        • 死锁检测:fcntl 有,信号量没有。

        • 自动释放:fcntl 锁随进程终止自动释放。

      3. mutex/condvar:线程标准方案;NPTL 允许跨进程(POSIX 未强制要求)。

      4. eventfd(2.6.22+):单 8-byte 整数计数器;read 阻塞(值=0 时),write 增加;可 select/poll/epoll。 适合作为「生产者-消费者」通知。

      When:协调文件访问用 file lock;通用资源协调用 sem;线程间用 mutex/cond。

      43.4 IPC 对比

      What:5 个维度——name/identifier、functionality、accessibility、persistence、performance。

      Why:选 IPC 的客观依据。

      How——Table 43-1 标识符与 handle:

      类型 标识符 Handle

      管道

      无名

      fd

      FIFO

      pathname

      fd

      UNIX domain 套接字

      pathname

      fd

      INET 套接字

      IP + port

      fd

      SysV msg/sem/shm

      IPC key

      IPC id (整数)

      POSIX 消息队列

      pathname

      mqd_t

      POSIX 信号量

      pathname

      sem_t *

      POSIX 共享内存

      pathname

      fd

      匿名映射

      mmap 文件

      pathname

      fd

      flock

      pathname

      fd

      fcntl

      pathname

      fd

      Table 43-2 持久性:

      设施 可达性 持久性

      管道

      仅相关进程

      process

      FIFO

      权限

      process

      UNIX domain socket

      权限

      process

      INET domain socket

      任意

      process

      SysV message queue

      权限

      kernel

      SysV semaphore

      权限

      kernel

      SysV shm

      权限

      kernel

      POSIX mq

      权限

      kernel

      POSIX named sem

      权限

      kernel

      POSIX shm

      权限

      kernel

      匿名 mapping

      仅相关

      process

      mmap file

      权限

      filesystem

      flock

      open()

      process

      fcntl

      open()

      process

      When:每个具体决策查这两张表。

      43.5 POSIX vs SysV IPC 设计选择

      What:SysV IPC 没有像 fd 那样的引用计数——内核不知道进程是否仍在用,决定何时删除对象需要额外协调。

      Why:SysV 比较难做到「最后一个用户退出时自动清理」。

      How

      1. SysV 缺点:connectionless(无 handle);integer key + integer id 不像 pathname + fd;删除决定难。

      2. POSIX 优点:kernel counts open references;接口一致(pathname + 类似 fd 的 handle)。

      When:新代码用 POSIX;遇到老 SysV 代码要理解其怪异设计。

      43.7 eventfd

      What:Linux 2.6.22 引入——一个 8-byte 整数计数器,read 阻塞到非零、write 增加。

      Why:替代 pipe(2)+read/write 同步——一个 fd 干两份工(write 通知 + read 消费)。

      How

      #include <sys/eventfd.h>
      int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
      uint64_t cnt = 1;
      write(efd, &cnt, sizeof(cnt));   /* 通知 */
      uint64_t out;
      read(efd, &out, sizeof(out));    /* 返回并清零 */

      When:多进程 fork 后共享此 fd,用作事件通知,配合 select/poll/epoll。

      三、关键图表

      本章无独立编号图表——所有内容已分布在 Table 43-1/43-2(IPC 标识符/handle 与可达性/持久性)。

      四、思维导图

      mindmap
        root((第 43 章 IPC 概述))
          三大分类
            communication
            synchronization
            signals
          数据传输
            byte stream
              管道 FIFO 流套接字
            message
              SysV POSIX mq 数据报
          共享内存
            SysV shm
            POSIX shm
            mmap file anon
          同步设施
            semaphores
            file locks flock fcntl
            mutex condvar
            eventfd
          选择维度
            标识符 handle
            functionality
            accessibility
            persistence
            performance
          SysV vs POSIX
            SysV 老但移植
            POSIX 现代
            推荐新代码用 POSIX

      五、重点与易错点

      1. IPC 选型第一问题:要通信还是同步?——通信的管道/FIFO/msg;同步的 sem/flock/eventfd。

      2. 数据传输有「破坏性读」语义——读走就没了;共享内存的读非破坏。要广播用 UDP 多播/广播(不破坏)。

      3. 空管道 read 阻塞(默认)——这是自动同步;如果不想阻塞就 O_NONBLOCKfcntl() 设非阻塞。

      4. 共享内存不默认同步——必须额外用 sem 或 file lock 协调;初学者常忘记导致数据损坏。

      5. SysV IPC 没有引用计数——多个进程同时持有时无法「最末一进程自动清理」;POSIX IPC 有。

      6. POSIX mq 支持 select/poll/epoll(Linux 实现)——但 SUSv3 未保证;其他 UNIX 不一定有。

      7. fd-based IPC 可与 select/poll/epoll 集成(管、套接字、FIFO、eventfd、POSIX mq)——写 server 时这是必备条件。

      8. fcntl() record lock 有死锁检测——内核会自动拒绝死锁请求;SysV sem 没有,写 lock ordering 是必须的。

      9. fcntl() 锁随进程终止自动释放——更安全;SysV sem 的 SEM_UNDO 不完全可靠。

      10. eventfd 用一个 8-byte uint64——read 返回并清零、write 累加;适合生产者-消费者事件流。

      11. FIFO 的名称持久性与数据持久性分开——FIFO 文件名在文件系统持续存在,pipe 数据随 fd 关闭消失。

      12. 所有 fd-based IPC 都受 file descriptor limits 影响——RLIMIT_NOFILE 决定 fd 数。

      13. 跨章衔接:第 44 章 管道/FIFO,第 45-48 章 SysV IPC,第 49 章 mmap,第 51 章 POSIX IPC,第 53 章 POSIX sem、第 54 章 POSIX shm、第 52 章 POSIX mq,第 56-61 章 socket。

      Asciidoc lint check

      asciidoctor: 无警告。