【linux】进程间通信(匿名管道)

对于本篇文章我们采取三段论:是什么 为什么 怎么办。

目录

  • 进程间为什么要通信?
  • 进程间如何通信?
  • 进程间怎么通信?
    • 匿名管道:
      • 匿名管道原理:
      • 代码示例:
      • 匿名管道的情况与特征:

进程间为什么要通信?

进程间也是需要某种协同的。
协同应该怎么理解呢?
在这里插入图片描述
那么协同的前提必然是进行通信
但是通信的信息也是有类别的,比如说单纯的数据信息,或者控制信息…

了解了这个话题我们还要在阐述一个事实,进程间具有独立性:比如关闭你的QQ但是不影响微信。
进程 = 内核数据结构 + 数据与代码
那么这两份东西每个进程都是有独一份的,数据与代码会写时拷贝,所以不影响我们这个结论。

进程间如何通信?

这里我们要明确两个共识:
a. 进程间通信是有成本的(这个会在后边的代码中有验证)
b. 进程间通信的前提:让两个进程看到同一块内存资源

我们画图进行理解一下:
在这里插入图片描述

进程间怎么通信?

开始这个话题之前我们需要先知道一个东西:
互联网有大量标准的存在,否则为什么不同品牌的手机,不同大陆的手机厂商,用着不一样的硬件设备最后却能进行通信?
就是因为标准的存在!

所以我们进程间通信也有标准,这里我们只谈System V
这个标准提供了一些通信方式:

  1. 消息队列
  2. 共享内存
  3. 信号量

但是,人们刚接触通信时肯定是先想到尽量复用源代码进行通信的,故我们暂且不谈以上的方式(未来会谈)。
所以我们利用源代码设计出了两种方式

  1. 匿名管道
  2. 有名管道

这里我们先说匿名管道,因为他简单。

匿名管道:

匿名管道原理:

下图是一幅进程,文件与磁盘的简略图:
在这里插入图片描述
当对此文件以另一种方式打开时,变化如下
在这里插入图片描述
为什么答案是否定的呢?
在这里插入图片描述

那么当前进程fork()(创建子进程)会发生什么变化?
在这里插入图片描述
所以,现在我们就可以以普通文件为切入点理解匿名管道了

首先父进程打开同一个文件以“w”“r”方式,然后在进行创建子进程,
子进程会继承父进程的文件系统那一套数据结构,
这样他们就有了公共的一块内存,也就是那段内核缓冲区,
我们此时就可以一个进程向其中写入,另一个读取
在这里插入图片描述

但是我们匿名管道并不是普通文件,

  • 第一:我们的匿名管道不需要与磁盘进行交互了,因此,设计者要重新设计出一个新的通信接口
  • 第二:我们的管道只允许单向通信,因为他简单!所以我们fork之后要关闭一个进程的w和另一个进程的r

因此我们现在要理解一种现象以及两个问题:
现象:为什么我们的父子进程会向同一块显示屏打印数据

问题1:既然未来要关闭不需要的fd,那我们可不可以直接不打开呢?
问题2:可以不关闭吗?

对于这种现象是因为我们的bash父进程就已经打开了fd为0 1 2的文件描述符,所以bash的子进程们都继承了,所以他们会向同一块fd为1指向的内存进行疯狂输出并刷新到显示屏外设

对于问题1:不可以,因为这样子进程就不会继承了。
对于问题2:可以,单位了防止我们有意外操作建议关闭!

代码示例:

话说了这么多我们总得有理论实践,我们会使用pipe接口+fork来创建管道。

下段这80行的代码可以帮助我们理解匿名管道的情况与特征:
代码中会有注释:

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

const int SIZE = 1024;

std::string GetOtherMessage()
{
    static int cnt = 1;
    int id = getpid();
    std::string MessageCnt = std::to_string(cnt++);
    std::string ChildId = std::to_string(id);

    return "MessageCnt: " + MessageCnt + " child id: " + ChildId +  + " ";
}

子进程进行写入,但是我另外写了一段程序进行获取一段动态的信息。也就是如上的函数
void SubProcessWrite(int wfd)
{
    std::string message = "I am child,";
    while (true)
    {
        std::string info = message + GetOtherMessage();
        write(wfd, info.c_str(), info.size());
        sleep(1);
    }
}

父进程进行读
void FatherProcessRead(int rfd)
{
    char buffer[SIZE] = {0};
    while (true)
    {
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "father get message:" << buffer << std::endl;
        }
    }
}

int main()
{
    int pipefd[2];
    int ret = pipe(pipefd);
    if (ret == -1)
    {
        std::cerr << "errno: " << errno << " errstring: " << std::strerror(errno) << std::endl;
        return 1;
    }
    pid_t id = fork();
    if (id == 0)
    {
        std::cout << "我是子进程,已经关闭了0了" << std::endl;
        // 子进程,进行写,关闭r
        close(pipefd[0]);

        SubProcessWrite(pipefd[1]);
        close(pipefd[1]);
        exit(0);
    }
    std::cout << "我是父进程,已经关闭了1了" << std::endl;

    // 父进程,进行读,关闭w
    close(pipefd[1]);

    FatherProcessRead(pipefd[0]);
    close(pipefd[0]);

    // 父进程进行等待
    int rid = waitpid(id, nullptr, 0);
    if (rid > 0)
    {
        std::cout << "wait sucess" << std::endl;
    }

    return 0;
}

匿名管道的情况与特征:

对于下边情况的验证我们都可以通过对上边的程序进行修改得到结果。

四种情况:
在这里插入图片描述

在这里插入图片描述
对于2,我们可以将上面的程序进行一下修改在这里插入图片描述
同时让父进程sleep更长的时间,得到管道的大小为64kb(ubuntu22.04)

在这里插入图片描述
在这里插入图片描述
至于为什么不会阻塞是因为管道已经失效了。
在这里插入图片描述
首先我们要对这种情况进行一个探究,读端已经被关闭,说明写再多也没有用,OS不会允许这种浪费时空的东西存在,会直接杀掉写进程。
用什么杀死呢?
OS发送13号信号进行终止。

此时的这个管道也叫做broken pipe。


五种特征:

  1. 匿名管道:只能用于有血缘关系的进程之间,常用于父子进程。

  2. 管道之间自带进程的同步机制。
    (同步理解为多执行流代码的时候,具有顺序性)
    在这里插入图片描述

  3. 管道文件的生命周期是随进程的

  4. 管道文件再通信的时候是面向字节流的(可以认为write的次数与read的次数不是一一匹配的,就像你用的水是从自然界收集来的,自然界用了10小时收集的水,你1分钟用完了)

  5. 管道的通信模式是一种特殊的半双工模式
    我们先来说一下全双工模式->类似于我们吵架时,我们可以同时说话
    半双工就是一个人说,一个人不说,或者相反过来
    而我们这个特殊的半双工就特殊在只能单向,只能一段说话,另一端不说话。

最后我们在输出最后一个结论:
我们在上文提到过:我们具有同步机制,但其实这不是一定的,当我们每次写入数据小于PIPE_BUF时才会具有这种机制,也叫作原子态(atomic)
在这里插入图片描述
匿名管道就结束啦!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

双指针(C++)

文章目录 1、移动零2、复写零3、快乐数4、盛最多水的容器5、有效三角形的个数6、和为s的两个数7、三数之和8、四数之和 需要理解的是&#xff0c;双指针并非只有指针&#xff0c;双指针的意思是两个位置。比如对于数组来说&#xff0c;两个下标也是双指针。当然&#xff0c;也可…

二叉树中的最大路径和 - LeetCode 热题 50

大家好&#xff01;我是曾续缘&#x1f638; 今天是《LeetCode 热题 100》系列 发车第 50 天 二叉树第 15 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 二叉树中的最大路径和 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一…

冯喜运:5.2黄金触底反弹今日还会跌吗?原油最新行情分析策略

【黄金消息面分析】&#xff1a;周三(5月1日)&#xff0c;受美联储主席鲍威尔讲话影响&#xff0c;现货黄金价格暴涨近33美元&#xff1b;周四亚市早盘&#xff0c;现货黄金守住涨幅&#xff0c;目前交投于2323.69美元/盎司。此外&#xff0c;美联储主席鲍威尔(Jerome Powell)未…

RoNID:通过生成可靠标签与聚类友好型表征来实现新意图的发现

论文地址&#xff1a;https://arxiv.org/abs/2404.08977 原文地址&#xff1a;intents-are-not-going-away-ronid-is-a-new-intent-discovery-framework 2024 年 4 月 26 日 Robust New Intent Discovery&#xff08;RoNID&#xff09;框架致力于在开放域场景中识别已知意图并合…

树莓派控制步进电机(上):硬件连接

目录 说明 硬件连接 DM542的连接方法 树莓派的连接方法 参考文献 说明 最近需要测试树莓派控制步进电机的功能&#xff0c;在查阅网上资料的基础上做了一些整理和测试&#xff0c;特别记录在此。这里我们使用的是树莓派4B开发板&#xff0c;步进电机为6线两相步进电机&am…

探索APP分发的含义和小猪APP分发平台的优势(小猪APP分发平台)

一、APP分发的基本含义 APP分发指的是将开发完成的APP通过特定渠道推广给用户的过程。这个过程涵盖探索APP分发的含义和小猪APP分发平台的优势了从提交、审核到发布的全过程探索APP分发的含义和小猪APP分发平台的优势&#xff0c;目的是让APP更好地触达潜在用户探索APP分发的含…

AI时代程序员必备的22个网站,你了解多少?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

2024-05-02 商业分析-杭州小万科技-商业模式分析

摘要: 对杭州小万科技的商业模式进行分析,以对其做出客观的评估。 杭州小万科技的资料: 杭州小万科技有限公司 - 企知道 (qizhidao.com) 杭州小万科技有限公司网站备案查询 - 天眼查 (tianyancha.com) 杭州小万科技有限公司 - 爱企查 (baidu.com) ​ 2023年年报:

高中数学:三角函数公式汇总及推导

一、定义 常用三角函数值 参考&#xff1a; 三角函数定义 二、基本三角函数及相互关系 sinx cosx tanx cscx secx cotx 函数间相互关系 参考&#xff1a; cosx、sinx、tanx的函数图像与性质 secx、cscx、cotx函数图像及相关关系 三、诱导公式 口诀&#xff1a;奇变…

【Python文字识别】基于HyperLPR3实现车牌检测和识别(Python版本快速部署)

闲来无事&#xff0c;想复现一下网上的基于YOLO v5的单目测距算法。然后就突然想在这个场景下搞一下车牌识别&#xff0c;于是就有了这篇文章。今天就给大家分享基于HyperLPR3实现车牌检测和识别。 原创作者&#xff1a;RS迷途小书童 博客地址&#xff1a;https://blog.csdn.ne…

商务谈判模拟口才训练方案(3篇)

商务谈判模拟口才训练方案&#xff08;3篇&#xff09; 商务谈判模拟口才训练方案&#xff08;一&#xff09; 一、训练目标 本训练方案旨在提高参与者在商务谈判中的口才表达能力&#xff0c;包括清晰表达、有效倾听、应对挑战和构建信任等能力。 二、训练内容 基础口才训练…

android天气实战

页面绘制 问题1、下拉框需要背景为透明 我懒得写全部省份就写了5个所以不需要往下 图标准备 iconfont-阿里巴巴矢量图标库几坤年没来这了好怀念啊&#xff0c;图标库选择下雨的图标等 准备网络请求 0、API接口准备 api免费七日天气接口API 未来一周天气预报api (tianqiap…

智慧能源数据监控平台

随着科技的飞速发展&#xff0c;能源管理已逐渐从传统的粗放型向精细化、智能化转变。在这个转型过程中&#xff0c;HiWoo Cloud平台的智慧能源数据监控平台以其独特的技术优势和创新理念&#xff0c;正引领着能源管理的新潮流。 一、智慧能源数据监控平台的概念 智慧能源数据…

Vue 工程化开发入门

Vue开发的两种方式&#xff1a; 核心包传统开发模式&#xff1a;基于html/css/js文件&#xff0c;直接引入核心包&#xff0c;开发Vue工程化开发模式&#xff1a;基于构建工具的环境中开发Vue 这里选择Vue cli脚手架 进行开发&#xff0c;搜索教程自行下载。 组件化开发 一个页…

【R语言】描述性数据分析与数据可视化

我们处理的变量可以分为两类&#xff0c;一类是连续型变量&#xff0c;另一类叫做分类型变量&#xff0c;其中对于连续型变量&#xff0c;如果服从正态分布就用平均值填充NA&#xff0c;不服从正态分布就用中位数填充NA&#xff0c;对于分类型变量&#xff0c;不管是有序的&…

蓝桥杯单片机省赛——第八届“基于单片机的电子钟程序设计与调试”程序部分

往期回顾 第三届蓝桥杯单片机省赛 第四届蓝桥杯单片机省赛 第五届蓝桥杯单片机省赛 第六届蓝桥杯单片机省赛 第七届蓝桥杯单片机省赛 文章目录 往期回顾一、前期准备二、代码详情1.基础代码蜂鸣器/继电器/led/定时器之类的代码 2.按键详解按键写法讲解 3.驱动的处理驱动写法讲…

Linux学习笔记:进程间的通信.共享内存shm

共享内存shm 什么是共享内存shm共享内存的特点关键函数ftokshmgetshmatshmdtshmctl 代码示例 什么是共享内存shm 进程间通信的前提:必须让不同的进程看到同一份资源,并且这个资源是OS提供的 而共享内存(Share memory)就是在内核共享内存区找一块物理内存空间,并允许多个进程共…

远距离、高品质、低延迟、高保真——SA316无线音频模块带您探索新的音频体验

SA316系列产品分为发射端模块SA316S-TX,SA316F30和接收端模块SA316-RX&#xff0c;该系列方案采用了无线高品质的语音传输芯片来设计&#xff0c;它可以支持外部 PCM / IIS 双模数字音频接口&#xff0c;同时模块为客户提供了标准化的串行接口&#xff0c;使用者可通过串口指令…

使用QT完成如图的游戏登录界面 使用信号和槽完成密文明文密码转换,重置账号和密码,登录校验 详细代码在主页下载

头文件: #ifndef LOGINWIDGET_H #define LOGINWIDGET_H #include <QLineEdit> #include <QPushButton> #include <QWidget> class LoginWidget : public QWidget {Q_OBJECT public: LoginWidget(QWidget *parent = 0); ~LoginWidget(); public slots: …

全新神经网络架构KAN一夜爆火!200参数顶30万,MIT华人一作 | 最新快讯

白交衡宇发自凹非寺 量子位公众号 QbitAI 一种全新的神经网络架构 KAN&#xff0c;诞生了&#xff01; 与传统的 MLP 架构截然不同&#xff0c;且能用更少的参数在数学、物理问题上取得更高精度。 比如&#xff0c;200 个参数的 KANs&#xff0c;就能复现 DeepMind 用 30 万参数…