I — 进程间通信

进程间通信(IPC)是不同进程之间交换数据的方式。由于进程有独立的虚拟地址空间,它们不能直接访问彼此的内存,需要内核提供通信机制。

IPC 机制对比

机制数据单元特点场景
管道 (Pipe)字节流单向、父子进程常见Shell 管道 (`ls
命名管道 (FIFO)字节流有文件系统名称、任意两进程独立进程间通信
共享内存字节块最快(无数据拷贝)、需要同步高性能场景
消息队列消息(有边界)异步消息传递、OS 维护生命周期多进程任务分发
信号 (Signal)整数信号编号异步通知、少量信息进程终止(SIGKILL)、定时(SIGALRM)
套接字 (Socket)字节流 / 数据报跨网络、跨主机网络服务
mmap 文件映射字节块文件→内存映射大文件读写、数据库

管道 (Anonymous Pipe)

管道由 pipe() 调用创建,返回两个文件描述符:fd[0](读端)和 fd[1](写端)。内容写入后,从另一端顺序读取。

int fd[2];
pipe(fd);
if (fork() == 0) {
 close(fd[0]); // 子进程关闭读端
 write(fd[1], "hello", 5);
} else {
 close(fd[1]); // 父进程关闭写端
 read(fd[0], buf, 5);
}

内核中的管道使用环形缓冲区实现,默认容量 64KB。管道是半双工——数据只能单向流动;需要双向通信则创建两个管道。

命名管道 (FIFO)

与管道相同,但在文件系统中有一个名字(通过 mkfifo 建立),任意两个知道该名字的进程都可以打开并使用。生命期独立于创建它的进程。

共享内存

共享内存是最快的 IPC 方式——数据不需要在内核和用户空间之间拷贝,双方直接读写同一物理页:

// 创建共享内存段
int shm_id = shmget(key, 4096, IPC_CREAT | 0666);
char *addr = shmat(shm_id, NULL, 0);
// 现在 addr 可被创建进程和所有附加进程同时访问

缺点:需要额外的同步机制(如信号量)来防止竞争条件。共享内存本身只是一块被映射到两个进程的物理页,不提供任何同步保证。

信号 (Signal)

信号是异步通知,携带的信息极小(只有信号编号)。进程可以注册信号处理函数,或选择忽略/阻塞信号。

信号编号含义
SIGINT2Ctrl+C
SIGKILL9强制终止(不能被捕获或忽略)
SIGSEGV11段错误(非法内存访问)
SIGALRM14定时器到期
SIGCHLD17子进程状态变化

本章与其他模块的链接