Linux:进程间通信---匿名管道

news2025/4/26 3:16:00

文章目录

      • 1. 进程间通信
        • 1.1 什么是进程间通信?
        • 1.2 为什么进程要进行进程间通信?
        • 1.3 怎么实现进程间通信?
      • 2. 匿名管道
        • 2.1 匿名管道的原理
        • 2.2 匿名管道的系统接口
        • 2.3 匿名管道的使用
        • 2.4 匿名管道的运用场景

  • 序:在上一篇文章中我们知道了如何连接动静态库,动态库和静态库的链接有什么区别,以及动态库在系统内核部分是如何被访问的等知识,而今天我们将进入一个新的模块—进程间通信,聊到这个,我们首先想到的是两个进程是如何进行通信的,通信又是为了什么呢?以及,不是说两个进程之间不是有独立性吗?这和进程间通信岂不是矛盾了?本章我将从管道的角度,带大家认识什么是进程间通信。

1. 进程间通信

1.1 什么是进程间通信?

进程间通信:两个或者多个进程实现数据层面的交互,因为进程独立性的存在,导致进程通信的成本比较高。

1.2 为什么进程要进行进程间通信?

a. 发送基本数据
b. 发送命令
c. 完成进程间的某种协同
d. 通知

总结下来就是为了让进程通信起来!!!
而通信是有成本的,所以我们就要打破进程的独立性,让两个进程能进行通信

1.3 怎么实现进程间通信?

a. 进程通信的的本质:必须让不同的进程看到同一份“资源”
b. “资源”:特定形式的内存空间。
c. 这个“资源”谁提供?一般是操作系统,为什么不是我们进程中的其中一个呢?假设是其中一个进程提供的的,那么这个“资源”就是该进程独有的,破坏进程的独立性了,所以,只能由第三方空间提供“资源”。
d. 我们进程访问这个空间,进行通信,本质就是在访问操作系统!!!进程代表的就是用户,“资源”从创建,到使用(一般),到释放------都离不开系统调用接口!!!
e. 基于文件级别的通信方式—管道

从底层设计,从接口设计,都要由操作系统独立设计,一般操作系统,会有一个独立的通信模块----隶属于文件系统----IPC通信模块---->定制标准----进程间通信是有标准的

两种标准:
System V(本机内部) && posix(网络)

其中System V的标准如下:
System V IPC{
System V —消息队列
System V —共享内存
System V —信号量
}

在后续的文章中,我会逐一将System中的概念拿出来谈一谈的。

2. 匿名管道

2.1 匿名管道的原理

问题一:什么是管道?

在这里插入图片描述
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

在讲管道之前,让我们来看一张图片:
在这里插入图片描述
对于一个进程来说,一开始task_struct指向的files_struct中有struct file * 数组,里面会默认打开三个文件,stdin、stdout、stderr,分别对应键盘和显示器,其中stdout和stderr都是打开的显示器,所以显示器文件同时被两个指针指向,此时显示器的引用计数为2。

当我们打开一个文件时,首先,该文件会有自己的文件描述符,并且有自己的struct file结构体,该结构体有对应的inode,file_operators和文件页缓冲区。

当我们要将数据存储到磁盘中时,会先将数据存放在文件页缓冲区中,后续才会刷新到磁盘内,同理要修改磁盘中的内容,要先把磁盘中的内容加载到文件页缓冲区中,修改后再刷新到磁盘当中去。

那么,有没有一种文件,他有对应文件描述符,有自己的struct file,页有inode、files_operators和文件页缓冲区,但是该文件页缓冲区中的内容并不会刷新到磁盘当中去。答案肯定是有的,这种文件就是一种内存级文件,也就是我们今天的主角—管道!!!所以管道是一个文件,一个内存级文件!!!

问题二:那么问题来了,这个管道为什么能让我们进行进程间通信呢?

当我们创建了一个进程后,我们调用系统调用生成一个子进程时,子进程会有自己独立的task_struct结构体,但是该结构体中的struct file * fd数组中的内容,在进行fork时会拷贝给子进程,也就是说父子进程指向了同一份资源!!!而我们一开始就说了进程间通信的的本质就是必须让不同的进程看到同一份“资源”,而管道就能够很好的符合这一点!!!

问题三:进程间要怎么使用管道来进行通信?

要想知道进程要怎么使用管道来进行通信,我们就要知道管道的原理,之前我们说过了,管道是一个内存级文件,他能使两个父子进程看到同一份资源。

如图:
在这里插入图片描述
当我们的进程同时以读和写的方式打开同一个文件时,会有两个文件描述符指向该文件,只是打开方式不同,一个只能写,一个只能读,此时我们发现该进程,既能向该文件中写数据也能向该文件中读数据。

当我们调用系统调用fork时,此时创建的子进程会将父进程的files_struct中的struct file * fd数组拷贝到子进程中,所以子进程的3号文件描述符和4号文件描述符也会分别指向以r方式打开的文件和以w方式打开的文件。此时,父子进程就同时访问了一个文件缓冲区!!!这就符合了进程间通信的本质,让两个进程看到了同一份资源!!!

需要注意的是,我们不能让父子进程同时向文件读数据或写数据,不然的话就可能会出现数据错乱的情况,这样会导致数据不一致问题,所以,在我们使用管道让两个进程进行进程间通信时,一定是一个读数据,一个写数据!!!

2.2 匿名管道的系统接口

在这里插入图片描述

Pipefd是输出型参数,,将文件描述符带出来,让用户使用。
Pipefd[0]:读端
Pipefd[1]:写端

管道的特征:

1. 具有血缘关系(父子,爷孙,兄弟…)(通过fork调用)的进程进行进程间通信
2. 管道只能单向通信,如果要双向通信,就建立多个管道
3. 父子进程是会进程协同的,同步与互斥的—保护管道文件的数据安全
4. 管道是面向字节流的,只是单纯的字节。
5. 管道是基于文件的,而文件的生命周期是进程的,所以,当进程结束,操作系统会自动回收文件,将对应文件的引用计数清零。

2.3 匿名管道的使用

说了这么多,让我们来使用一下pipe,去看看这个pipe怎么使用吧!!!

代码如下:

#include<iostream>
#include<cstdlib> //stdio.h
#include<unistd.h>
#include<string>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>

#define N 2
#define NUM 1024

using namespace std;

//child
void Write(int wfd)
{
    string s="hello,i am child";
    pid_t self=getpid();
    char buffer[NUM];
    while(true)
    {
        sleep(1);
        //构建发送字符串
        buffer[0]=0;//类似于'\0',字符串清空
        snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,number++);
        //发送给父进程
        write(wfd,buffer,strlen(buffer));
    }
}

//father
void Read(int rfd)
{
    char buffer[NUM];
    int cnt=0;
    while(true)
    {
        //sleep(3);
        buffer[0]=0;
        ssize_t n=read(rfd,buffer,sizeof(buffer));//返回字符串的大小
        if(n>0)
        {
            buffer[n]=0;//0 == '\0'
            cout<<"father get msg:"<<buffer<<"father pid:"<<getpid()<<endl;
        }
        else if (n==0) 
        {
            cout<<"read file done!"<<endl;
            break;
        }
        else break;
        if(cnt++==5) break;
    }

}

int main()

{
    int pipefd[N]={0};
    int n=pipe(pipefd);
    if(n<0)return 1;
    //cout<<"pipefd[0]: "<<pipefd[0]<<endl<<"pipefd[1]: "<<pipefd[1]<<endl;
    pid_t id = fork();
    if(id<0)return 2;
    if(id==0){
        //child
        close(pipefd[0]);
        //IPC code
        Write(pipefd[1]);
        close(pipefd[1]);
        exit(0);
    }
    //parent
    close(pipefd[1]);
    //IPC code
    Read(pipefd[0]);
    close(pipefd[0]);
    cout<<"father close read fd"<<endl;
    sleep(5);
    int status=0;
    pid_t rid=waitpid(id,&status,0);
    if(rid<0){
        return 3;
    }
    cout<<"waited success "<<"exit code:"<<((status>>8)&0xFF)<<\
    " exit signal:"<<(status&0x7F)<<endl;
    cout<<"father quit!"<<endl;
    return 0;
}

管道的4种情况:

1. 读写正常,管道如果是空的,读端就要阻塞。(也就是写端还没写入,读端只能阻塞,不能读数据)
2. 读写端正常,管道如果被写满了,写端就要阻塞。(注:ulimit -a:用来查看操作系统对一些重要资源的限制,里面就能查看一个pipe size大小是多大。)
3. 读端正常读,写端关闭,读端就会读到0位置,表明读到pipe文件的结尾,不会被阻塞。
4. 写端正常写入,读端关闭,操作系统就会要杀掉正在写入的进程(怎么杀掉?答案是通过信号杀掉,注:操作系统是不会做抵消,浪费等类似的工作的,如果做了,那就是操作系统的bug)(此时,被杀死进程的信号是13号信号,SIGPIPE)

2.4 匿名管道的运用场景

我们(使用匿名管道)实现一个简易版的进程池!!!

问题一:什么是池化技术?

我们平常的系统调用是有成本的,所以提前将可能要申请的系统资源准备好,放在一个空间里面,这就是池化技术,是用来提高访问效率的,比如进程池,就是提前fork()好几个进程,等用户要调用时,直接就给用户分配,而不需要再去调用系统调用!!!

调用各个进程的时候要遵循负载均衡!!!

负载均衡:
1. 随机数
2. 轮询(轮转)

让我们来实现一个进程池:

点击下面的链接,自动跳转到线程池的代码:

使用匿名管道实现一个简易版的进程池

总结:

本篇文章从进程间通信的定义出发,由浅入深,从理论到原理解析,从解析到实例分析,最后再到运用的场景,我们不仅知道了进程间通信的本质就是不同进程间看到同一份资源,还知道了管道的系统调用和管道的使用,通过总结四种情况和五中特征的方式了解深入了解了管道的使用情况!!!

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

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

相关文章

深度学习小记(包括pytorch 还有一些神经网络架构)

这个是用来增加深度学习的知识面或者就是记录一些常用的命令,会不断的更新 import torchvision.transforms as transforms toPIL transforms.ToPILImage()#可以把tensor转换为Image类型的 imgtoPIL(img) #利用save就可以保存下来 img.save("/opt/data/private/stable_si…

【数据可视化-32】全球住房市场分析(2015-2024 年)数据集可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

DAX Studio将PowerBI与EXCEL连接

DAX Studio将PowerBI与EXCEL连接 具体步骤如下&#xff1a; 第一步&#xff1a;先打开一个PowerBI的文件&#xff0c;在外部工具栏里打开DAXStudio&#xff0c;如图&#xff1a; 第二步&#xff1a;DAXStudio界面&#xff0c;点击Advanced选项卡-->Analyze in Excel&#…

使用spring boot vue 上传mp4转码为dash并播放

1.前端实现 <template><div class"video-upload"><el-uploadclass"upload-demo"action"/api/upload":before-upload"beforeUpload":on-success"handleSuccess":on-error"handleError":show-file-…

深入理解指针 (1)

1.内存和地址 1.1内存 1.1.1内存的使用和管理 &#xff08;1&#xff09;内存划分为一个个的内存单元&#xff0c;每个内存单元的大小是1个字节&#xff0c;一个内存单元可以存放8个bit。 &#xff08;2&#xff09;每个内存单元有一个编号&#xff0c;内存单元的编号在计…

Leetcode98、230:二叉搜索树——递归学习

什么是二叉搜索树&#xff1a;右子树节点 > 根节点 > 左子树节点&#xff0c; 二叉搜索树中的搜索&#xff0c;返回给定值val所在的树节点 终止条件为传进来的节点为空、或者节点的值 val值&#xff0c;返回这个节点&#xff1b; 单程递归逻辑&#xff1a;定义一个resu…

15. LangChain多模态应用开发:融合文本、图像与语音

引言&#xff1a;当AI学会"看听说想" 2025年某智慧医院的多模态问诊系统&#xff0c;通过同时分析患者CT影像、语音描述和电子病历&#xff0c;将误诊率降低42%。本文将基于LangChain多模态框架与Deepseek-R1&#xff0c;手把手构建能理解复合信息的智能系统。 一、…

2022李宏毅老师机器学习课程笔记

机器学习笔记目录 1.绪论&#xff08;内容概述&#xff09;2.机器学习和深度学习的基本概念transformer 1.绪论&#xff08;内容概述&#xff09; 机器学习&#xff1a;让机器找一个函数&#xff0c;通过函数输出想要的结果。应用举例&#xff1a;语音识别&#xff0c;图像识别…

笔试强训:Day2

一、字符串中找出连续最长的数字串(双指针) 字符串中找出连续最长的数字串_牛客题霸_牛客网 #include <iostream> #include <string> #include <cctype> using namespace std;int main() {//双指针string str;cin>>str;int nstr.size();int begin-1,l…

linux合并命令(一行执行多个命令)的几种方式总结

背景&#xff1a; 最近安装配置机器&#xff0c;需要手打很多命令。又不能使用docker&#xff0c;所以就使用iTerm2连接多台服务器&#xff0c;然后move session到一个窗口中&#xff0c;shift command i使用XSHELL类似的撰写功能&#xff0c;就可以一次在多台服务器命令窗口…

基于归纳共形预测的大型视觉-语言模型中预测集的**数据驱动校准**

摘要 本研究通过分离共形预测&#xff08;SCP&#xff09;框架&#xff0c;解决了大型视觉语言模型&#xff08;LVLMs&#xff09;在视觉问答&#xff08;VQA&#xff09;任务中幻觉缓解的关键挑战。虽然LVLMs在多模态推理方面表现出色&#xff0c;但它们的输出常常表现出具有…

docker学习笔记5-docker中启动Mysql的最佳实践

一、查找目录文件位置 1、mysql的配置文件路径 /etc/mysql/conf.d 2、mysql的数据目录 /var/lib/mysql 3、环境变量 4、端口 mysql的默认端口3306。 二、启动命令 1、启动命令说明 docker run -d -p 3306:3306 -v /app/myconf:/etc/mysql/conf.d # 挂载配置目录 -v…

从零开始搭建Django博客③--前端界面实现

本文主要在Ubuntu环境上搭建&#xff0c;为便于研究理解&#xff0c;采用SSH连接在虚拟机里的ubuntu-24.04.2-desktop系统搭建&#xff0c;当涉及一些文件操作部分便于通过桌面化进行理解&#xff0c;通过Nginx代理绑定域名&#xff0c;对外发布。 此为从零开始搭建Django博客…

系统与网络安全------弹性交换网络(3)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 STP协议 环路的危害 单点故障 PC之间的互通链路仅仅存在1个 任何一条链路出现问题&#xff0c;PC之间都会无法通信 解决办法 提高网络可靠性 增加冗余/备份链路 增加备份链路后交换网络上产生二层环路 …

Cursor 配置 MCP Tool

文章目录 1、MCP Tool 的集合2、一个 demo :Sequential Thinking2.1、搜索一个 MCP Tool 获取 command 命令2.2、在 Cursor 配置2.3、配置状态检查与修正(解决网络问题)检查解决办法 2.4、使用 1、MCP Tool 的集合 https://smithery.ai/ 2、一个 demo :Sequential Thinking …

【金仓数据库征文】-《深入探索金仓数据库:从基础到实战》

目录 前言 什么是金仓数据库&#xff1f; 金仓数据库的特点 金仓数据库的核心特点 金仓数据库与其他数据库的对比 金仓数据库的安装 常见的语句 总结 前言 为助力开发者、运维人员及技术爱好者快速掌握这一工具&#xff0c;本文将系统性地介绍金仓数据库的核心知识。内…

RocketMQ 主题与队列的协同作用解析(既然队列存储在不同的集群中,那要主题有什么用呢?)---管理命令、配置安装

学习之前呢需要会使用linux的基础命令 一.RocketMQ 主题与队列的协同作用解析 在 RocketMQ 中&#xff0c;‌主题&#xff08;Topic&#xff09;‌与‌队列&#xff08;Queue&#xff09;‌的协同设计实现了消息系统的逻辑抽象与物理存储分离。虽然队列实际存储在不同集群的 B…

从岗位依附到能力生态:AI革命下“什么叫就业”的重构与价值

在人工智能(AI)技术深刻重塑社会生产关系的当下,“就业”这一概念正经历着从“职业绑定”到“能力变现”的范式转移。本文将从传统就业观的解构、AI赋能艺术教育的价值逻辑、以及未来就业形态的进化方向三个维度,探讨技术驱动下就业的本质变革,并揭示AI技术如何通过教育创…

海外版高端Apple科技汽车共享投资理财系统

这一款PHP海外版高端Apple、科技汽车、共享投资理财系统phplaravel框架。

企业为何要禁止“片断引用开源软件代码”?一文看透!

开篇故事&#xff1a;一段“开源代码”引发的百亿级灾难 某电商平台为快速上线新功能&#xff0c;从GitHub复制了一段“高性能加密算法”代码到支付系统中。 半年后&#xff0c;黑客通过该代码中的隐藏后门&#xff0c;盗取百万用户信用卡信息。 事后调查&#xff1a;这段代…