一、进程间通信目的
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止
- 时要通知父进程)。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
如何理解通信的本质问题:
(1)操作系统需要直接或者间接给通信双方的进程提供"内存空间"。
(2)要通信的进程,必须要看到同一份公共的资源。
- 模块化实现:不同通信方式本质上是操作系统不同模块提供的资源:
- 文件系统提供→管道通信
- System V通信模块提供→共享内存/信号量/消息队列
- 资源类型决定通信方式:
- 内存块→共享内存
- 计数器→信号量
- 队列→消息队列
二、什么是管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个"管道"。
三、站在文件描述符角度-深度理解管道
管道是父进程创通过调用管道,分别以读和写方式打开一个文件,并通过fork创建子进程的方式,被子进程继承下去,进而形成一条通信管道
- ,管道文件的作用与特点
- 通信本质: 专门用于两个进程间通信的特殊文件类型
- 两个进程看到同一个管道文件
- 实现方法:通过父进程打开文件后fork创建子进程完成
- 继承机制:子进程会继承父进程的文件描述符表内容
- 文件标识:类似宿舍号和班级名称,通过相同文件描述符标识同一文件
- 实现方法:通过父进程打开文件后fork创建子进程完成
- 匿名管道的概念
- 命名特点:内存级文件没有文件名标识

cpp
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
int fds[2];
int n = pipe(fds);
pid_t id = fork();
if(id==0)
{
close(fds[0]);
int cnt=0;
const char*s = "我是子进程,我正在给你发消息";
while (1)
{
cnt++;
char buffer[1024];
snprintf(buffer,sizeof(buffer),"child->parent say:%s[%d]\n",s,cnt);
write(fds[1],buffer,strlen(buffer));
sleep(1);
}
exit(0);
}
close(fds[1]);
while (1)
{
char buffer[1024];
//如果管道中没有了数据,读端在读,默认会直接阻塞当前正在读取的进程。
ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);
if(s>0)//返回值是获取字节数的个数
{
buffer[s]=0;
cout<<buffer<<endl;
}
}
n=waitpid(id,nullptr,0);
close(fds[0]);
return 0;
}
管道是一个固定大小的缓冲区,当写端一直写,读端不读,缓冲区会被写满,写满之后不能再写了,如果在写会把以前写入的数据覆盖,写端写满会发生阻塞等对方进行读取。
若是子进程写入一条消息后立即关闭写端(文件描述符),父进程读取到read返回值那就是是0。
若是读端关闭,写端口一直写,操作系统会终止写端口,会给写端口发送信号终止写端。
四、管道的五大特征
- 文件依托性
- 基础机制: 管道基于文件实现
- 生命周期: 随进程创建和销毁,当所有关联进程退出时管道自动释放
- 类比特性: 与普通文件特性一致,进程退出后相关资源自动回收
- 血缘通信
- 适用范围: 专用于具有血缘关系的进程间通信
- 父子进程通信(最典型场景)
- 兄弟进程通信(需通过共同父进程建立管道)
- 多代进程通信(如祖父-孙子进程)
- 实现前提: 必须在fork()前创建管道才能实现共享
- 适用范围: 专用于具有血缘关系的进程间通信
- 字节流特性
- 数据特征: 不区分消息边界,按字节流处理
- 读写特点:
- 写入方不考虑接收方的数据解析需求
- 读取方按最大可读字节数获取数据
- 对比说明: 不同于消息队列等有明确消息边界机制
- 半双工通信
- 通信方向: 任一时刻只允许单向数据传输
- 特殊形式: 单向通信是半双工的特例
- 实现限制: 需要两个管道才能实现双向通信
- 同步互斥机制
- 阻塞控制:
- 写满阻塞:管道缓冲区满时写入进程自动阻塞
- 读空阻塞:管道空时读取进程自动阻塞
- 异常处理:
- 读端关闭时继续写入会触发SIGPIPE
- 写端关闭时读取会立即返回0(EOF)
- 保护机制: 内部实现共享资源保护,确保数据一致性
- 阻塞控制: