Linux IPC:管道与FIFO汇总整理

embedded/2025/1/15 23:12:43/

管道(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.ppmy.cn/embedded/154227.html

相关文章

神经网络

“损失函数 王木头学科学-哔哩哔哩_bilibili 一、transformer和注意力机制的本质&#xff0c;以及编码和解码的结构及其与注意力机制的关系&#xff0c;帮助理解transformer的优势和应用场景。 00:01 - 介绍transformer是人工智能主流技术&#xff0c;大语言模型GBT是在其基础…

宁德时代C++后端开发面试题及参考答案

请阐述面向对象的三大特性。 面向对象编程有三大特性,分别是封装、继承和多态。 封装是指将数据和操作数据的方法绑定在一起,对数据的访问和操作进行限制。这样做的好处是可以隐藏对象的内部细节,只暴露必要的接口给外部。例如,我们可以把一个汽车类的内部引擎状态、速度等…

macOS 如何终止端口占用的进程 ?

您是否遇到过这样的情况&#xff1a;您试图在 Mac 上启动服务器或服务&#xff0c;却被告知端口已被占用&#xff1f;当您试图使用的端口被另一个进程占用时&#xff0c;就会出现此问题。在本教程中&#xff0c;我们将指导您完成在 macOS 上识别和终止这些进程的步骤&#xff0…

C#学习笔记 --- 简单应用

1.operator 运算符重载&#xff1a;使自定义类可以当做操作数一样进行使用。规则自己定。 2.partial 分部类&#xff1a; 同名方法写在不同位置&#xff0c;可以当成一个类使用。 3.索引器&#xff1a;使自定义类可以像数组一样通过索引值 访问到对应的数据。 4.params 数…

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…

Kubernetes1.28 编译 kubeadm修改证书有效期到 100年.并更新k8s集群证书

文章目录 前言一、资源准备1. 下载对应源码2.安装编译工具3.安装并设置golang 二、修改证书有效期1.修改证书有效期2.修改 CA 证书有效期 三、编译kubeadm四、使用新kubeadm方式1.当部署新集群时,使用该kubeadm进行初始化2.替换现有集群kubeadm操作 前言 kubeadm 默认证书为一…

浅谈云计算10 | 服务器虚拟化支撑技术(长文)

服务器虚拟化支撑技术 一、CPU虚拟化技术1.1 CPU虚拟化概述1.1.1 定义与目标1.1.2 关键技术原理 1.2 CPU虚拟化技术实现1.2.1 模拟执行机制1.2.2 硬件辅助虚拟化技术1.2.3 调度策略 三、内存虚拟化技术3.1 内存虚拟化原理3.1.1 地址转换机制3.1.2 内存管理策略 3.2 内存虚拟化实…

最左前缀匹配原则

最左前缀匹配原则&#xff08;Leftmost Prefix Rule&#xff09;是数据库中多列索引&#xff08;也称为复合索引或组合索引&#xff09;使用时的一个重要概念。以下是对最左匹配原则的较为全面的解释&#xff1a; 定义 最左前缀匹配原则指的是&#xff0c;在多列索引中&#xf…