【Note】《深入理解Linux内核》 第十九章:深入理解 Linux 进程通信机制

《深入理解Linux内核》 第十九章:深入理解 Linux 进程通信机制(Process Communication)

关键词:IPC、信号、管道、FIFO、消息队列、信号量、共享内存、套接字、内核对象、同步机制


一、进程通信概述

1.1 为什么需要进程通信

在 Linux 系统中,进程是资源隔离的基本单位,彼此间通常无法直接访问彼此的地址空间。因此需要一套机制,使得多个进程之间可以:

  • 交换数据
  • 同步行为
  • 发送通知
  • 共享资源

这些功能由 Linux IPC(Inter-Process Communication)子系统实现。

1.2 IPC 分类

类型 描述
信号 最基本的异步通知机制
管道/FIFO 字节流通信机制,面向数据流
消息队列 面向结构化消息,先进先出
信号量 同步与互斥,典型用于资源控制
共享内存 多进程映射同一段内存,效率最高
套接字 网络与本地通信统一抽象,支持多协议

二、信号(Signal)

2.1 概述

信号是进程间最早被引入的通信机制,本质上是一个异步事件通知。

示例信号 描述
SIGINT 中断(Ctrl+C)
SIGTERM 终止进程请求
SIGKILL 无条件终止进程(不可捕获)
SIGCHLD 子进程结束通知父进程

2.2 信号相关系统调用

  • kill(pid, sig):向指定进程或进程组发送信号;
  • signal(sig, handler):设置信号处理函数;
  • sigaction():更强大的信号控制;
  • sigprocmask():阻塞/允许某些信号;
  • sigqueue():带参数的信号发送。

2.3 内核实现

  • 每个进程结构 task_struct 中包含 sigpendingsignal 字段;
  • 信号通过 do_signal() 派发;
  • 某些信号是不可忽略/不可屏蔽的(如 SIGKILL);
  • Linux 通过实时信号(SIGRTMIN ~ SIGRTMAX)支持有序队列与附加参数。

三、管道与 FIFO

3.1 管道(pipe)

管道是最基本的 IPC 数据流机制,数据在两个进程间以 FIFO 形式流动。

c 复制代码
int pipe(int pipefd[2]); // pipefd[0]=read, pipefd[1]=write

特点:

  • 半双工(单向通信);
  • 父子进程间常见用途;
  • 基于内核中的 pipe_inode_info 结构实现;
  • 使用缓冲区环形队列实现数据传输。

3.2 命名管道(FIFO)

可跨进程、不限于亲缘关系:

bash 复制代码
mkfifo /tmp/myfifo

特点:

  • 是一种特殊文件;
  • 可在 shell 中使用 < /tmp/myfifo> /tmp/myfifo

3.3 内核实现

  • 管道是内核中一种特殊的字符设备;
  • 每个 pipe 被表示为一个 inode;
  • 内核用 struct pipe_inode_info 管理缓冲区、读写端等。

四、消息队列(Message Queues)

4.1 概述

消息队列允许进程以"消息"为单位进行通信,每条消息是结构化数据(类型 + 数据内容)。

c 复制代码
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

4.2 内核数据结构

c 复制代码
struct msg_queue {
    struct list_head q_messages;
    ...
};
  • 所有消息链入 q_messages
  • 支持按类型匹配接收;
  • 消息大小有限制(msgmax)。

4.3 特点

  • 支持异步发送、同步接收;
  • 按优先级接收;
  • 属于 System V IPC 之一;
  • 支持权限与 quota 控制。

五、信号量(Semaphores)

5.1 概述

信号量提供一种同步机制,用于控制多个进程对共享资源的访问,支持阻塞和非阻塞操作。

c 复制代码
int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, size_t nsops);
  • 每个信号量集合由 semid 索引;
  • semop() 支持加锁/解锁操作(P/V操作);
  • 使用计数表示资源状态。

5.2 内核结构

c 复制代码
struct sem_array {
    struct sem *sem_base;
    ...
};
  • Linux 信号量集支持原子操作;
  • 支持 undo 机制,在进程终止时自动释放资源;
  • 属于 System V IPC 范畴,现代内核中逐渐被 futex 和 pthread 替代。

六、共享内存(Shared Memory)

6.1 概述

多个进程将一段物理内存映射到各自虚拟地址空间,实现高效通信。

c 复制代码
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);

特点:

  • 速度最快的 IPC;
  • 通常配合信号量/互斥锁使用;
  • 属于 System V IPC;

6.2 内核实现

  • 使用 shmid_kernel 描述共享段;
  • 实质上是内核为各进程映射同一段物理页;
  • 页表项被多个进程共享;
  • 写时复制(COW)策略在此无效。

七、套接字通信(Socket)

7.1 套接字种类

类型 描述
UNIX 域套接字 仅限本机通信,文件系统路径寻址
INET 套接字 网络通信,使用 IP 与端口
STREAM 面向连接,类似 TCP
DGRAM 无连接,类似 UDP

7.2 创建通信过程

c 复制代码
int socket(int domain, int type, int protocol);
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • socket 通信是最通用的进程通信方式;
  • 在内核中通过 sock 结构表示;
  • 数据缓冲使用 sk_buff 结构管理。

八、Linux IPC 统一接口

Linux 提供 /proc/sysvipc/ 系统接口与 ipcs 工具来统一查看 IPC 对象:

bash 复制代码
ipcs -m   # 共享内存
ipcs -q   # 消息队列
ipcs -s   # 信号量

可以使用 ipcrm 删除对象。


九、IPC 命名空间与隔离(Namespace)

9.1 IPC Namespace

每个 IPC 对象(shm、sem、msg)都可以在命名空间中隔离,容器技术(如 Docker)广泛使用。

  • 创建 IPC namespace:unshare --ipc
  • 每个命名空间有独立的 IPC 资源空间;
  • 安全、稳定、互不干扰。

十、内核源码参考路径

文件路径 作用描述
kernel/signal.c 信号实现与分发
ipc/msg.c 消息队列实现
ipc/sem.c 信号量实现
ipc/shm.c 共享内存实现
fs/pipe.c 管道与 FIFO 实现
net/unix/af_unix.c UNIX 域 socket 实现
include/linux/ipc_namespace.h IPC 命名空间
include/linux/shm.h 共享内存头文件

十一、小结

  • Linux 提供多种 IPC 机制,各有优缺点与适用场景;
  • 信号适合简单事件通知;
  • 管道与 FIFO 适合流式数据传输;
  • 消息队列支持结构化数据传递;
  • 信号量用于同步资源控制;
  • 共享内存效率最高,但需额外同步手段;
  • 套接字最通用,跨主机通信也适用;
  • IPC 命名空间提升系统隔离性与安全性。
相关推荐
Dirschs15 分钟前
【Ubuntu22.04安装ROS Noetic】
linux·ubuntu·ros
qianshanxue1121 分钟前
ubuntu 操作记录
linux
AmosTian3 小时前
【系统与工具】Linux——Linux简介、安装、简单使用
linux·运维·服务器
YC运维4 小时前
RIP实验以及核心原理
运维·网络·智能路由器
leo__5205 小时前
自动化运维:使用Ansible简化日常任务
运维·自动化·ansible
霖005 小时前
C++学习笔记三
运维·开发语言·c++·笔记·学习·fpga开发
CodeWithMe5 小时前
【Note】《Kafka: The Definitive Guide》 第九章:Kafka 管理与运维实战
运维·分布式·kafka
这我可不懂6 小时前
Python 项目快速部署到 Linux 服务器基础教程
linux·服务器·python
车车不吃香菇6 小时前
java idea 本地debug linux服务
java·linux·intellij-idea