当前位置: 首页 > article >正文

Linux IPC:管道与FIFO汇总整理

管道(Pipes)和先进先出(FIFOs,也称为命名管道)都是Linux中用于进程间通信(IPC)的机制。它们允许数据从一个进程流向另一个进程,类似于命令行中的管道操作符 |。下面详细介绍这两种机制以及如何使用它们。

2a430394f0f240d3b89830522fee97bf.jpeg

管道 (Pipes)

管道是一种特殊的文件,它允许数据从一个进程(通常称为生产者)流向另一个进程(通常称为消费者)。管道是半双工的,意味着数据只能单向流动。

特点

  • 管道存在于内存中,不是真正的文件系统对象。
  • 管道只能用于具有亲缘关系的进程之间,通常是父子进程。
  • 管道是半双工的,即数据只能在一个方向上流动。
  • 管道的容量有限,当写入的数据超过管道的容量时,写入操作会被阻塞,直到消费者读取了一些数据。

创建管道

  • pipe():
    • int pipe(int pipefd[2]): 创建一个管道。
    • 参数pipefd是一个数组,包含两个文件描述符,第一个用于读取,第二个用于写入。

示例代码

以下是一个简单的例子,展示了如何使用管道在父子进程中传递数据:

1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <sys/wait.h>
6
7int main() {
8    int pipefd[2];
9    pid_t pid;
10
11    // 创建管道
12    if (pipe(pipefd) == -1) {
13        perror("pipe");
14        exit(EXIT_FAILURE);
15    }
16
17    // 创建子进程
18    pid = fork();
19    if (pid < 0) {
20        perror("fork");
21        exit(EXIT_FAILURE);
22    } else if (pid == 0) {  // 子进程
23        close(pipefd[1]);  // 关闭写端
24        char buffer[1024];
25        ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
26        if (bytes_read == -1) {
27            perror("read");
28            exit(EXIT_FAILURE);
29        }
30        buffer[bytes_read] = '\0';  // 确保字符串以空字符结尾
31        printf("子进程读取: %s\n", buffer);
32        close(pipefd[0]);
33        exit(EXIT_SUCCESS);
34    } else {  // 父进程
35        close(pipefd[0]);  // 关闭读端
36        const char *message = "Hello, World!";
37        ssize_t bytes_written = write(pipefd[1], message, strlen(message));
38        if (bytes_written == -1) {
39            perror("write");
40            exit(EXIT_FAILURE);
41        }
42        close(pipefd[1]);
43
44        // 等待子进程结束
45        wait(NULL);
46    }
47
48    return 0;
49}

FIFO (Named Pipes)

FIFO 或命名管道类似于管道,但它们是文件系统中的特殊文件,因此可以被任何进程访问。这意味着它们可以用于没有亲缘关系的进程之间进行通信。

特点

  • FIFO 是持久性的,即使创建它的进程不再存在,FIFO 仍然存在。
  • FIFO 可以被任何进程打开和使用,而不仅仅是父子进程。
  • FIFO 也是半双工的,即数据只能在一个方向上流动。
  • FIFO 的容量同样有限,当写入的数据超过 FIFO 的容量时,写入操作会被阻塞,直到消费者读取了一些数据。

创建 FIFO

  • mkfifo():
    • int mkfifo(const char *pathname, mode_t mode): 创建一个 FIFO。
    • 参数pathname指定 FIFO 的路径名,mode指定权限掩码。

示例代码

以下是一个简单的例子,展示了如何使用命名管道在两个进程之间传递数据:

1#include <unistd.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <sys/stat.h>
7
8#define FIFO_NAME "/tmp/myfifo"
9
10int main() {
11    int filedes;
12    char buffer[1024];
13
14    // 创建 FIFO
15    if (mkfifo(FIFO_NAME, S_IRUSR | S_IWUSR) == -1) {
16        if (errno != EEXIST) {
17            perror("mkfifo");
18            exit(EXIT_FAILURE);
19        }
20    }
21
22    // 读取进程
23    filedes = open(FIFO_NAME, O_RDONLY);
24    if (filedes == -1) {
25        perror("open");
26        exit(EXIT_FAILURE);
27    }
28
29    ssize_t bytes_read = read(filedes, buffer, sizeof(buffer) - 1);
30    if (bytes_read == -1) {
31        perror("read");
32        exit(EXIT_FAILURE);
33    }
34    buffer[bytes_read] = '\0';  // 确保字符串以空字符结尾
35    printf("读取进程: %s\n", buffer);
36    close(filedes);
37
38    // 写入进程
39    filedes = open(FIFO_NAME, O_WRONLY);
40    if (filedes == -1) {
41        perror("open");
42        exit(EXIT_FAILURE);
43    }
44
45    const char *message = "Hello, World!";
46    ssize_t bytes_written = write(filedes, message, strlen(message));
47    if (bytes_written == -1) {
48        perror("write");
49        exit(EXIT_FAILURE);
50    }
51    close(filedes);
52
53    return 0;
54}

注意事项

  • 在使用管道或 FIFO 之前,确保检查文件描述符的有效性。
  • 当使用 FIFO 时,确保至少有一个进程已经打开了 FIFO 的读端或写端,否则打开操作可能会失败。
  • 在使用完管道或 FIFO 后,记得关闭文件描述符以释放资源。
  • 在创建 FIFO 之后,确保在不再需要时删除它以释放文件系统资源。
  • 跨进程通信时,确保处理好同步问题,避免数据竞争或死锁。

管道和 FIFO 都是非常有用的进程间通信工具,它们可以简化数据在进程之间的传输过程。理解和熟练掌握这些机制对于编写可靠、高效的多进程程序非常重要。

 


http://www.kler.cn/a/502768.html

相关文章:

  • 【Rust自学】12.3. 重构 Pt.1:改善模块化
  • mermaid大全(语法、流程图、时序图、甘特图、饼图、用户旅行图、类图)
  • RocketMQ 知识速览
  • ubuntu官方软件包网站 字体设置
  • 深入探讨 Vue.js 的动态组件渲染与性能优化
  • 解决win11的vmvare和docker冲突
  • C#,图论与图算法,输出无向图“欧拉路径”的弗勒里(Fleury Algorithm)算法和源程序
  • css盒子水平垂直居中
  • 下载的stable diffudion 模型如何转换到diffusers可用的格式
  • SQLynx 数据库管理平台 3.6.0 全新发布:全面支持华为数据库和ClickHouse,代码提示更智能!
  • 软考信安21~网络设备安全
  • Android Room 构建问题:There are multiple good constructors
  • 备战春招—高频芯片设计面试题
  • DuckDB:星号(*)表达式完整指南
  • HIVE技术
  • 【AscendC】tiling方案设计不当引起的一个时隐时现的bug
  • CNN中模型的参数量与FLOPs计算
  • Spring MVC数据绑定POJO类型
  • 【动态规划-矩阵】6.最大正方形
  • Linux 子系统 Ubuntu 安装MySQL 8
  • 【Apache Paimon】-- 为什么选择将 Spark 与 Paimon 集成,解决什么问题?
  • 国产linux系统(银河麒麟,统信uos)使用 PageOffice 实现后台生成单个PDF文档
  • 虚假星标:GitHub上的“刷星”乱象与应对之道
  • 如何解决HTML和CSS相关情况下会导致页面布局不稳定?
  • ImportError: attempted relative import with no known parent package 报错的解决!
  • 2025年,华为认证HCIA、HCIP、HCIE 该如何选择?