进程间通信(IPC)的方法:命名管道

news2024/11/26 14:41:53

      使用管道时,一个进程的输出可成为另外一个进程的输入。
      命名管道(Named pipe或FIFO)是一种类似于管道的特殊文件,但在文件系统上有一个名称,它允许以先进先出(FIFO, first in, first out)的方式存储有限数量的数据。它的使用类似于消息传递,其中一个进程发送一条信息,其它进程接收它。数据以FIFO方式以高吞吐速度进入管道。但是,队列一次可以容纳的最大数据大小为16页(pages)或65536字节。它实际上使用了一块内核内存。
      命名管道是在文件系统中作为一个特殊的设备文件而存在。不同祖先的进程之间可以通过命名管道共享数据。当共享命名管道的进程执行完所有的I/O操作以后,命名管道将继续保存在文件系统中,以便以后使用,除非调用unlink。通过命名管道,不相关的进程也能交换数据。一旦已经用mkfifo函数创建了一个FIFO,就可用open打开它。实际上,一般的文件I/O函数(close、read、write、unlink等)都可用于FIFO。
      只要FIFO有空间,write函数就是非阻塞的,但read会阻塞当前线程。
      命名管道总结
      (1).同步(用于单向管道);
      (2).队列大小为16页(page),每页4096字节。只要数据消耗足够快,数据大小就没有限制;
      (3).单个管道的单向通信;
      (4).以线性方式读写;
      (5).自动内存管理。
      注:以上内容主要来自网络整理。
      如果父进程和子进程之间互相发送接收数据,需要两根管道,如以下测试代码:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#include <error.h>
#include <iostream>
#include <thread>
#include <cctype>

typedef struct message {
    int pid;
    char ch;
} message;

int main(int argc, char **argv)
{
    const char *named_pipe1 = "/tmp/named_pipe1", *named_pipe2 = "/tmp/named_pipe22";
    unlink(named_pipe1); // deletes a name from the file system
    unlink(named_pipe2);

    if (mkfifo(named_pipe1, 0666) < 0 || mkfifo(named_pipe2, 0666) < 0) { // make a FIFO special file(a named pipe), if the file exists, the call will fail
        fprintf(stderr, "fail to mkfifo: %s\n", strerror(errno));
        return -1;
    }

    struct stat buffer1, buffer2;
    if (stat(named_pipe1, &buffer1) != 0 || stat(named_pipe1, &buffer2) != 0) { // retrieve information about the file pointed to by pathname
        fprintf(stderr, "fail to stat: %s\n", strerror(errno));
        return -1;
    }

    pid_t pid = fork();
    if (pid < 0) {
        fprintf(stderr, "fail to fork\n");
        return -1;
    }

    if (pid == 0) { // child process
        auto fd1 = open(named_pipe1, O_RDONLY); // read only
        auto fd2 = open(named_pipe2, O_WRONLY); // write only
        if (fd1 < 0 || fd2 < 0) {
            fprintf(stderr, "fail to open: %d, %s\n", pid, strerror(errno));
            exit(1);
        }

        for (int i = 0; i < 5; ++i) {
            message msg;
            auto ret = read(fd1, &msg, sizeof(msg));
            if (ret < 0) {
                fprintf(stderr, "fail to read: %d, %d %s\n", pid, i, strerror(errno));
                exit(1);
            }

            msg.ch = std::toupper(msg.ch);
            ret = write(fd2, &msg, sizeof(msg));
            if (ret < 0) {
                fprintf(stderr, "fail to write: %d, %d, %s\n", pid, i, strerror(errno));
                exit(1);
            }

            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }

        close(fd1);
        close(fd2);
        exit(0);
    }

    if (pid > 0) { // parent process
        auto fd1 = open(named_pipe1, O_WRONLY); // write only
        auto fd2 = open(named_pipe2, O_RDONLY); // read only
        if (fd1 < 0 || fd2 < 0) {
            fprintf(stderr, "fail to open: %d, %s\n", pid, strerror(errno));
            exit(1);
        }

        for (unsigned char i = 0; i < 5; ++i) {
            message msg = {pid, 'a'+i};

            auto ret = write(fd1, &msg, sizeof(msg));
            if (ret < 0) {
                fprintf(stderr, "fail to write: %d, %d, %s\n", pid, i, strerror(errno));
                exit(1);
            }

            fprintf(stdout, "src char: %c\n", msg.ch);

            ret = read(fd2, &msg, sizeof(msg));
            if (ret < 0) {
                fprintf(stderr, "fail to read: %d, %d, %s\n", pid, i, strerror(errno));
                exit(1);
            }

            fprintf(stdout, "dst char: %c\n", msg.ch);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }

        close(fd1);
        close(fd2);

        int status;
        auto pid2 = wait(&status); // system call suspends execution of the calling thread until one of its children terminates
        fprintf(stdout, "process ID of the terminated child: %d\n", pid2);
        if (WIFEXITED(status)) { // returns true if the child terminated normally
            fprintf(stdout, "child process ended with: exit(%d)\n", WEXITSTATUS(status));
        }
        if (WIFSIGNALED(status)) { // returns true if the child process was terminated by a signal
            fprintf(stderr, "child process ended with: kill -%d\n", WTERMSIG(status));
        }
    }

    unlink(named_pipe1); // deletes a name from the file system
    unlink(named_pipe2);
    fprintf(stdout, "====== test finish ======\n");
    return 0;
}

      build.sh内容如下:

#! /bin/bash

if [ -d build ]; then
    echo "build directory already exists, it does not need to be created again"
else
    mkdir -p build
fi

cd build
cmake ..
make

rc=$?
if [[ ${rc} != 0 ]];then
    echo "#### ERROR: please check ####"
    exit ${rc}
fi

echo "==== build finish ===="

      CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.22)
project(samples_multi_process)

set(CMAKE_BUILD_TYPE Release) # only works under linux
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -std=c++17")

file(GLOB samples ${PROJECT_SOURCE_DIR}/test_*.cpp)
#message(STATUS "samples: ${samples}")

foreach(sample ${samples})
    string(REGEX MATCH "[^/]+$" name ${sample})
    string(REPLACE ".cpp" "" exec_name ${name})
    #message(STATUS "exec name: ${exec_name}")

    add_executable(${exec_name} ${sample})
endforeach()

      执行结果如下图所示:

      GitHub:https://github.com/fengbingchun/Linux_Code_Test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/993146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(STM32H5系列)STM32H573RIT6、STM32H573RIV6、STM32H573ZIT6嵌入式微控制器基于Cortex®-M33内核

一、应用 工业&#xff08;PLC、工业电机控制、泵和压缩机&#xff09; 智能家居&#xff08;空调、冰箱、冰柜、中央警报系统、洗衣机&#xff09; 个人电子产品&#xff08;键盘、智能手机、物联网标签、跟踪设备&#xff09; 智能城市&#xff08;工业通信、照明控制、数字…

2023秋冬系列丨追求本真的自然纯粹之美

2023年08月&#xff0c;上海&#xff0c;ZESH泽尚&#xff0c;中国轻奢皮具品牌宣布推出2023全新秋冬系列包袋&#xff0c;以“自然之道&#xff0c;纯粹之美”为主题重新定义东方美学。品牌建立之初就坚持贯彻东方美学设计与精湛制作工艺融合的理念。此次秋冬系列从中式禅宗学…

EagleSDR USB HAT FT600

给EagleSDR做了个USB 3.0的子卡&#xff0c;采用FT600方案&#xff0c;实物如下&#xff1a; 用FT600DataStreamerDemoApp测试&#xff0c;速度如下&#xff1a; 由于FT600是16bit的接口&#xff0c;如果用FT601的32bit接口&#xff0c;性能应该还会有大幅提升。 测试代码很简…

通过Idea或命令将本地项目上传至git

通过Idea或命令将本地项目上传至git 一、Git创建仓库 1、登录Gitee账号&#xff0c;点击新建 2、填写如下相关信息&#xff0c;点击创建 3、在此处可以复制项目链接 二、Idea配置和解绑git&#xff0c;提交项目 1、idea打开项目&#xff0c;操作如下 2、在弹框里选择…

【监控系统】Promethus整合Alertmanager监控告警邮件通知

【监控系统】Promethus整合Alertmanager监控告警邮件通知 Alertmanager是一种开源软件&#xff0c;用于管理和报警监视警报。它与Prometheus紧密集成&#xff0c;后者是一种流行的开源监视和警报系统。Alertmanager从多个源接收警报和通知&#xff0c;并根据一组配置规则来决定…

Linux中的用户和用户组

su和exit命令 su命令就是用于账户切换的系统命令&#xff0c;其来源英文单词:Switch User 语法: su [-] [用户名] - 符号是可选的&#xff0c;表示是否在切换用户后加载环境变量 &#xff08;建议带上&#xff09;参数:用户名&#xff0c;表示要切换的用户&#xff0c;用户名也…

怎么提高自己当众讲话的能力?

当众讲话是一项重要的沟通技能&#xff0c;它可以帮助你在各种场合中表达自己的观点、影响他人&#xff0c;并建立自信。虽然对很多人来说&#xff0c;当众讲话可能是一项挑战&#xff0c;但通过一些实践和技巧&#xff0c;你可以提高自己的当众讲话能力。下面是一些方法&#…

Java开发之Redis核心内容【面试篇 完结版】

文章目录 前言一、redis使用场景1. 知识分布2. 缓存穿透① 问题引入② 举例说明③ 解决方案④ 实战面试 3. 缓存击穿① 问题引入② 举例说明③ 解决方案④ 实战面试 4. 缓存雪崩① 问题引入② 举例说明③ 解决方案④ 实战面试 5. 缓存-双写一致性① 问题引入② 举例说明③ 解决…

第3章_瑞萨MCU零基础入门系列教程之开发环境搭建与体验

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

滚珠螺杆螺母的加工方法

螺母就是螺帽&#xff0c;与螺栓或螺杆拧在一起用来起紧固作用的零件&#xff0c;螺母的用途十分广泛&#xff0c;那么它的加工方法&#xff0c;你了解吗&#xff1f;接下来&#xff0c;我们一起来看一下。 1、车削&#xff1a;最早使用的加工方法&#xff0c;加工螺母的工艺路…

Openlayers 教程 - feature(图形要素)点击和双击事件

Openlayers 教程 - feature&#xff08;图形要素&#xff09;点击和双击事件 核心代码完整代码&#xff1a;在线示例 地图中图形要素&#xff08;Feature&#xff09;的点击事件非常常用&#xff0c;曾经通过给整个地图绑定点击事件&#xff0c;然后判断图形要素&#xff08;Fe…

@Autowired自动装配对象为null,但是通过ApplicationContext注入的时候,却成功的注入了

错误&#xff1a;运行test1的时候&#xff0c;报bookController空指针异常 但是当我通过ApplicationContext注入的时候&#xff0c;却成功的注入了 原因是因为被注入的属性不能为静态属性&#xff01;&#xff01; 扩展&#xff1a; 1.一般而言&#xff0c;标注有(Component|…

RK3568-mpp(Media Process Platform)媒体处理软件平台

第一章 MPP 介绍 1.1 概述 瑞芯微提供的媒体处理软件平台(Media Process Platform,简称 MPP)是适用于瑞芯微芯片系列的通用媒体处理软件平台。 该平台对应用软件屏蔽了芯片相关的复杂底层处理,其目的是为了屏蔽不同芯片的差异,为使用者提供统一的视频媒体处理接口(Medi…

树,二叉树的概念与结构

&#x1f449;树&#xff0c;二叉树的概念与结构 1️⃣ .树的概念及结构1.1树的概念1.2树的相关概念1.3树的实现方式1.4树的实际用途 2️⃣.二叉树的概念及结构2.1二叉树的概念2.2特殊二叉树2.3二叉树的概念2.4二叉树的存储结构 所属专栏&#xff1a;初始数据结构❤️ &#x1…

【STL】模拟实现map和set {带头结点的红黑树;红黑树的核心结构;红黑树的迭代器;红黑树的插入和查找;map和set的封装}

模拟实现map和set map和set是红黑树的两种不同封装形式&#xff0c;底层使用同一颗泛型结构的红黑树。set是红黑树的K模型&#xff1b;map是红黑树的KV模型。 下面的代码和讲解着重体现红黑树的底层实现和map\set上层封装的衔接。关于二叉搜索树性质&#xff0c;map和set的介…

PowerDesigner 逆向工程

1、MySQL数据库连接&#xff08;JDBC方式&#xff09; 1.1 新建一个pdm&#xff0c;dbms选择mysql 1.2 Database - Connect 选择数据库连接 1.3 配置连接信息 数据库连接这里是通过一个配置文件来获取连接信息的&#xff0c;首次的话因为没有&#xff0c;所以我们需要选择…

采用BeautifulSouppqQueryxpath三种方法爬取电影详情页

采用三个框架BeautifulSoup&&pqQuery&&xpath&#xff0c;爬取知名的电影网页 主要是想体验这三种框架爬同一个网页的不同。 当然具体的不同我也说不清道不明 只能是体验了一把 以下代码都是本人亲自撸 如图所示&#xff0c;四个位置。分别爬取 电影名字 -&g…

docker 安装 Node-RED

Node-RED 是构建物联网应用程序的一个强大工具&#xff0c;使用可视化编程方法&#xff0c;连接起来执行任务。而homeassistant是家居智慧中枢&#xff0c;本文介绍如何安装Node-RED及HASS的插件 1、拉取镜像 docker pull nodered/node-red # 2、部署镜像 创建目录 mkidr -…

微调文本到图像扩散模型新方法DreamBooth,实现主题驱动生成(CVPR 2023)

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a; https://arxiv.org/pdf/2208.12242 项目主页&#xff1a;https://dreambooth.github.io/ 图1. 只需要拍摄某个主题&#xff08;左&#xff09;的几张图像&#xff08;通常为 3-5 张&…

Java守护线程的理解及应用

在Java中有两类线程&#xff0c;分别是User Thread&#xff08;用户线程&#xff09;和Daemon Thread&#xff08;守护线程&#xff09; 。 用户线程很好理解&#xff0c;我们日常开发中编写的业务逻辑代码&#xff0c;运行起来都是一个个用户线程。而守护线程相对来说则要特别…