进程间的通信-有名管道和无名管道

目录

[一、无名管道(Unnamed Pipe / pipe)半双工](#一、无名管道(Unnamed Pipe / pipe)半双工)

[1. 概念](#1. 概念)

[2. 创建方式](#2. 创建方式)

参数说明:

本质:

[3. 使用流程(重点)](#3. 使用流程(重点))

[4. 读写规则](#4. 读写规则)

[4.1 读端行为](#4.1 读端行为)

[4.2 写端行为](#4.2 写端行为)

[5. 管道关闭规则(非常重要)](#5. 管道关闭规则(非常重要))

[5.1 关闭写端](#5.1 关闭写端)

[5.2 关闭读端](#5.2 关闭读端)

进程通信本质关系

[二、有名管道(Named Pipe / FIFO)半双工](#二、有名管道(Named Pipe / FIFO)半双工)

[1. 概念](#1. 概念)

[2. 创建方式](#2. 创建方式)

方法1:命令创建

方法2:系统调用

打开方式

[3. 读写规则(和 pipe 类似)](#3. 读写规则(和 pipe 类似))

[5.1 读端](#5.1 读端)

[5.2 写端](#5.2 写端)

三、有名管道和无名管道特点对比


一、无名管道(Unnamed Pipe / pipe)半双工

1. 概念

无名管道是一种内核提供的临时通信缓冲区(队列) ,用于有亲缘关系的进程通信(父子进程)

特点:

  • 只能用于有关系的进程(父子/兄弟)
  • 没有文件名
  • 生命周期随进程结束而消失

2. 创建方式

cpp 复制代码
int pipe(int pipefd[2]);

参数说明:

  • pipefd[0]:读端(read end)

  • pipefd[1]

    本质:

    内核创建一个环形队列/缓冲区

    复制代码
    写端 → [  内核缓冲区(队列) ] → 读端

    3. 使用流程(重点)

  • 先 pipe,再 fork

    原因:fork 后子进程会继承父进程的 fd,从而共享同一个管道缓冲区

4. 读写规则

4.1 读端行为

情况1:管道无数据

read() → 阻塞(进入等待态)

情况2:管道有数据

read() → 立即返回,返回值 = 实际读取字节数

4.2 写端行为

情况1:正常写

write() → 写入缓冲区

情况2:读端关闭

write() → 触发 SIGPIPE 信号

进程默认退出(崩溃)

5. 管道关闭规则(非常重要)

5.1 关闭写端

如果:

  • 写端全部关闭
  • 读端仍在读

那么:read() → 返回 0 含义: 表示"文件结束 EOF"

5.2 关闭读端

如果:

  • 读端关闭
  • 写端还在写

那么:write() → 进程被 SIGPIPE 杀死

进程通信本质关系

pipe 是单向通信 :写进程 → 管道 → 读进程,如果需要双向通信:必须用 两个 pipe

二、有名管道(Named Pipe / FIFO)半双工

1. 概念

有名管道是: 有文件名的管道

本质仍然是:

  • 内核缓冲区(队列)
  • 但通过文件路径访问

2. 创建方式

方法1:命令创建

int pipe(int pipefd2);

参数说明:

  • pipefd[0]:读端(read end)
  • pipefd[1]:写端(write end)

本质:内核创建一个环形队列/缓冲区:写端 → 内核缓冲区(队列) → 读端

方法2:系统调用

cpp 复制代码
#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
//示例 mkfifo("myfifo", 0664);

打开方式

open("myfifo", O_RDONLY);

open("myfifo", O_WRONLY);

3. 读写规则(和 pipe 类似)

5.1 读端

  • 没数据 → 阻塞
  • 有数据 → 返回

5.2 写端

  • 无读者 → 阻塞或失败(取决于模式)
  • 有读者 → 正常写入

三、有名管道和无名管道特点对比

项目 无名管道 有名管道
是否有名字 没有 有文件名
使用范围 父子进程 任意进程
生命周期 随进程 文件存在即存在
通信方式 内存队列 文件路径访问
创建方式 pipe() mkfifo()