【linux】进程间的通讯(一)

[复制链接]
发表于 2026-10-3 22:46:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

进程之间是相互独立的,这既是 Linux 稳定性高的重要原因,也带来了一个现实问题:进程之间怎么交换数据?这就是进程间通信(IPC)要解决的问题。

一、认识进程间通信

进程间通信指两个或多个进程之间在数据层面发生交互。因为进程具备独立性,各自拥有独立的虚拟地址空间,一个进程拿不到另一个进程的内存,所以通信成本天然偏高——必须付出额外的代价。

二、进程间通信的目标

  • 本质:让不同的进程看到同一份“资源”,也就是同一块内存空间。
  • 来源:这份资源通常由操作系统提供,不属于某一个进程独有,因此不会破坏进程的独立性。
  • 路径:进程代表用户,资源从创建、使用到释放,全过程都是调用系统调用接口完成的。

三、进程间通信的发展与分类

一般操作系统都会有一个独立的通信模块,隶属于文件系统,IPC 通信模块会制定标准,所以进程间通信是有规范可循的。

1. 管道(文件级通信)

  • 匿名管道 pipe
  • 命名管道

2. System V IPC

  • System V 消息队列
  • System V 共享内存
  • System V 信号量

3. POSIX IPC

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

四、管道:Unix 里最古老的 IPC 形式

把一个进程的输出连接到另一个进程输入的那股数据流,就叫“管道”。

1. 匿名管道 pipe

  • 匿名管道本质上也是一个文件,只是缓冲区的数据不会刷新到磁盘上。
  • 刻意设计成读写两端,是为了保证管道只能单向通信。
#include <unistd.h>

// 功能:创建一无名管道
// 原型:int pipe(int fd[2])
// fd:文件描述符数组,fd[0] 表示读端,fd[1] 表示写端
// 返回值:成功返回 0,失败返回错误码
int pipe(int fd[2]);

匿名管道适用的一前提是:参与通信的两个进程必须有血缘关系,比如父子、兄弟、爷孙,最常见的是父子进程。

2. 用 fork 共享管道的原理

子进程的 PCB 是从父进程拷贝来的。如果父进程一开始用 pipe() 创建了匿名管道并且只打开了读端,那么子进程本该只能拿到写端(这样才能保证单向通信);但由于继承自父进程的写端,很容易导致单向失效。所以fork之后记得关掉多余的读写端。

int fd[2];
pipe(fd);

pid_t pid = fork();
if (pid < 0) {
    perror("fork");
} else if (pid == 0) {
    close(fd[0]);          // 子进程只写
    write(fd[1], buf, len);
    close(fd[1]);
} else {
    close(fd[1]);          // 父进程只读
    read(fd[0], buf, sizeof(buf));
    close(fd[0]);
}

3. 管道读写规则

  1. 读写端都正常时,管道为空,读端会阻塞。
  2. 读写端都正常时,管道被写满,写端会阻塞。
  3. 读端正常读、写端关闭,读端会读到 0,表示读到了管道末尾,不会被阻塞。
  4. 读端关闭、写端正常,内核会杀掉正在写入的进程(通过信号杀死)。

注意:管道大小是固定的,不同内核版本里大小会有所差异。

4. 管道的特点

  • 只能用于有共同祖先的进程之间通信:通常由一个进程创建管道,再调用 fork,之后父子进程就能用这条管道通信。
  • 管道提供流式服务,不保证消息边界。
  • 进程退出,管道随之释放,所以管道的生命周期随进程。
  • 内核会对管道操作做同步与互斥。
  • 管道是半双工的,数据只能单向流动;双方都要通信时必须建立两条管道。

五、小结

匿名管道是学习 IPC 的第一站,它的核心价值是“借文件之名,做内存之实”。搞清楚 fd 的读写端、fork 之后的端口关闭、阻塞读写规则这三件事,后面学命名管道、共享内存、消息队列时会顺畅很多。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表