Linux应用开发(8):Linux进程间通信(IPC):管道

本文详细介绍了Linux中的管道机制,包括无名管道和命名管道的概念、创建方法以及在各种场景下的应用,如父子进程通信、数据生成与过滤、并行处理等。
摘要由CSDN通过智能技术生成

Linux应用开发(7):Linux进程间通信(IPC):POSIX消息队列

1. 简述

        我们在前面已经介绍了进程间通信(IPC)常用的“消息队列”。本节将讲解另外一种常用的IPC机制,我们称作管道

        管道可以理解为一种特殊的文件,也可以理解为一种特殊的缓冲区,它允许两个进程通过一个半双工的通道进行数据通信。

2. 基本概念

        上面提到,管道是半双工的,数据只能向一个方向流动。在使用过程中,需要双方同时打开(也可以由父进程先打开,再由子进程继承)。管道分为无名管道和命名管道。

无名管道

无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程),它之所以成为无名管道,是因为它们不需要文件系统中的文件支持。管道的缓冲区是有限的。

命名管道

        相对于无名管道,命名管道是基于特殊的文件来进行通信的。在使用时,首先需要文件系统中有一个路径和名称,因此命名管道是可以允许不相关的进程进行通信。

3. 无名管道

        无名管道顾名思义,是没有被命名的管道,其存在于内存中,仅允许相关的两个进程间进行通信。

PS:可以联想到无名信号量和有名信号量,前者在内存中,仅允许关联进程同步,后者则可以在不相关联的进程间进行同步。

        无名管道的创建采用如下API。

#include <unistd.h>

int pipe(int fd[2]);

        fd 是一个整型数组,包含两个元素:fd[0] 用于读取,fd[1] 用于写入。

        无名管道例程。

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <sys/wait.h>


int main(int argc, char* argv[])

{

    int fds[2];

    pid_t pid;

    char buffer[50];

    if (pipe(fds) == -1) {

        perror("pipe");

        exit(EXIT_FAILURE);

    }

    /** 创建进程. */

    pid = fork();

    if (pid == -1) {

        perror("fork");

        exit(EXIT_FAILURE);

    }

    if (pid == 0) {

        /** 子进程:写入管道. */

        close(fds[0]); ///< 关闭读端

        write(fds[1], "Hello, Parent!", 15);

        close(fds[1]); ///< 写入后关闭写端

    } else {

        /** 父进程:读取管道。 */

        wait(NULL); ///< 等待子进程结束

        close(fds[1]); ///< 关闭写端

        read(fds[0], buffer, 50);

        close(fds[0]); ///< 读取后关闭读端

        printf("Parent Process: %s\n", buffer);

    }

    return 0;

}

4. 命名管道

        命名管道(FIFO)是一种特殊的文件,它允许不相关的进程通过一个命名的路径进行通信。与无名管道不同,命名管道在文件系统中有一个路径和名称。

创建命名管道的API如下。

#include <sys/stat.h>

int mkfifo(const char *path, mode_t mode);

        命名管道例程。

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/stat.h>


int main(int argc, char* argv[])

{

    /** 文件路径. */

    const char *fifo_name = "my_fifo";

    int fd;

    /** 创建命名管道. */

    if (mkfifo(fifo_name, 0666) == -1) {

        perror("mkfifo");

        exit(EXIT_FAILURE);

    }

    /** 打开命名管道进行写入. */

    fd = open(fifo_name, O_WRONLY);

    if (fd == -1) {

        perror("open");

        exit(EXIT_FAILURE);

    }

    /** 写入命名管道. */

    write(fd, "Hello, through FIFO!", 20);

    close(fd);

    /** 清理命名管道. */

    unlink(fifo_name);

    return 0;

}

5. 什么时候选择使用管道

(1)父子进程通信

在C++程序中,你可能需要创建子进程来执行特定的任务。管道可以用来在父进程和子进程之间安全地交换数据。

(2)进程生成和过滤

如果你的应用程序需要生成大量的数据,并且这些数据需要被另一个进程即时处理或过滤,管道可以有效地连接生成器和消费者。

(3)并行处理

在需要并行处理任务时,可以通过管道将任务的输出传递给其他进程,这些进程可以并行地处理数据。

(4)后台任务处理

当你需要在后台运行一个任务,并且不希望阻塞主进程时,可以使用管道来与后台任务通信。

(5)日志记录

管道可以用于实现日志系统,其中一个进程负责记录日志信息,而另一个进程负责监控和处理这些日志。

(6)信号传递

在多进程程序中,管道可以用来传递信号,如通知其他进程某个事件已经发生。

(7)资源共享

当多个进程需要访问同一个资源,但又需要协调访问以避免冲突时,可以使用管道来控制对资源的访问。

(8)简化线程使用

在某些情况下,使用管道进行进程间通信比使用线程更简单,尤其是在涉及复杂同步和锁管理的场景中。

(9)跨平台兼容性

如果你的C++应用程序需要在不同的操作系统上运行,使用管道可以提高代码的可移植性。

(10)模块化设计

在构建模块化的C++应用程序时,管道可以帮助你将不同的功能模块化为独立的进程,并通过管道进行通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值