进程间通信之管道

news2024/9/28 11:12:25

文章目录

    • 什么是进程间通信
      • 为什么进程要通信
      • 通信的本质是什么
    • 什么是管道
      • 匿名管道
      • 命名管道
    • 总结

什么是进程间通信

首先,通过前面的学习。我们知道了进程是具有独立性的,绝大多数情况下,一个进程挂掉了并不会影响另外一个进程。进程和进程之间拥有自己的进程地址空间和自己的页表。我们谁也不知道对方的存在。 但是,我们今天却要让这两个进程认识到对方的存在!而进程认识到对方的存在就是进程间通信

为什么进程要通信

前面我们知道,进程具有独立性。那么既然如此,具有独立性了还要通信。这不是听起来是一件十分矛盾的事情吗?实际上,进程间通信不仅不会和独立性产生矛盾,而且进程间进行通信的情况还是很多的!
进程间通信主要有如下的作用:

1.数据传输:一个进程需要将它的数据发送给另一个进程
2.资源共享:多个进程之间共享同样的资源
3.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件
4.进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程)

上述种种的情况都是需要两个进程间进行通信才能处理的。那么既然进程通信如此重要。那么如何让两个进程之间通信呢?通信的本质又是什么呢?

通信的本质是什么

在正式介绍进程间通信以前,我们先来看一看进程间通信的本质是什么。因为只有理解了本质,才能更好理解进程间通信的方式。 首先,我们知道进程是具有独立性的,也就是进程有自己的PCB,还有自己的进程地址空间。那么要想进行通信,首先第一步就是要有让两个进程能有一个双方都能看到的东西,然后两个进程在这个东西中进行交换资源的操作等等。 到这里,我们基本就可以确定了。进程间通信的本质是两个进程看到同一份资源!而这个资源可以是内存,文件等等一系列的资源
那么接下来我们就来看一看进程间通信的第一种方式:管道通信方式

什么是管道

首先,管道是进程间通信的一种方式。而进程间通信的本质是两个进程看到同一份资源,而管道就是这样一份资源。 Linux系统下一切皆文件。而管道本质就是一份在内存中打开的文件 而这个文件仅仅是用来让两个进程进行数据交换的,所以在通信结束完,管道的大小依旧是0。而Linux下有两种管道,首先我们先来看第一种:匿名管道。

匿名管道

所谓的匿名管道,就是没有名字的管道。对应使用的系统调用接口就是pipe接口 我们来看对应的系统接口说明:
在这里插入图片描述
这个接口的参数是一个数组,有两个元素,其实对应的就是两个被打开的文件fd ! 那么对于匿名管道而言,调用了这个接口以后,将会有两个文件同时被以读写方式打开!
你可能会好奇,为什么是读写方式打开,接下来和我们一起来回顾一下,操作系统在打开一个文件做了什么工作:
在这里插入图片描述
从图中就可以看出:以读写方式打开管道文件,那么一旦使用fork创建子进程,子进程一定也是以读写方式打开的文件!也就意味着,如果子进程只想读或者写,只要关闭另外的一种的方式即可! 而如何记忆哪一个是读端,哪一个是写端呢?

0是嘴巴,嘴巴用来说话,所以pipefd[0]是读端,对应的1是笔,笔用来写字,所以对应的pipefd[1]是写端

接下来,我们就来让父进程写入数据,然后让对应的子进程从管道读取数据:

/*
 *匿名管道操作
 * */
#include<iostream>
#include<unistd.h>
#include<cstring>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
int main()
{
  //父进程进行写入,子进程进行读取
    int pipefd[2]={0};
    int res=pipe(pipefd);
    if(res < 0)
   {
    std::cerr<<"cretepipe failed"<<'\n';
    return 1;
   }
  //管道创建成功 
    pid_t id=fork();
    //parent---->负责往管道写数据(字符串)
    if(id > 0)
    {
       const char* msg="father"; 
      //关闭读段
       close(pipefd[0]);
       write(pipefd[1],msg,strlen(msg));
    }
    //child---->负责读取消息,并把消息打印到屏幕
    else 
    {
       char buff[128];
       close(pipefd[1]);
       ssize_t s=read(pipefd[0],buff,sizeof(buff));
       buff[s]='\0';
       std::cout<<"child proc read :"<<buff<<std::endl;
       close(pipefd[0]);
    }
    pid_t ret=waitpid(id,nullptr,0);
    if(ret > 0)
    {
      std::cout<<"wait success!"<<std::endl;
      close(pipefd[1]);
    }
    
  return 0;
}

在这里插入图片描述
可以看到,我们这边一写入数据。子进程很快就可以读取到!这就是管道。管道是自带访问控制的,这个意味着管道一旦写端写满了,读取端不进行读取。那么写端也会被阻塞!同样的,读端把管道读空了,而写端不进行写入,那么读端同样会被阻塞!

/*
 *匿名管道操作
 * */
#include<iostream>
#include<unistd.h>
#include<cstring>
#include<ctime>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
int main()
{
  //父进程进行写入,子进程进行读取
    int pipefd[2]={0};
    int res=pipe(pipefd);
    if(res < 0)
   {
    std::cerr<<"cretepipe failed"<<'\n';
    return 1;
   }
  //管道创建成功 
    pid_t id=fork();
    //parent---->负责往管道写数据(字符串)
    if(id > 0)
    {
       const char* msg="father"; 
      //关闭读段
       close(pipefd[0]);
       sleep(5);
       write(pipefd[1],msg,strlen(msg));
    }
    //child---->负责读取消息,并把消息打印到屏幕
    else 
    {
       char buff[128];
       close(pipefd[1]);
       std::cout<<"before read "<<(unsigned)time(nullptr)<<std::endl;
       ssize_t s=read(pipefd[0],buff,sizeof(buff));
       buff[s]='\0';
       std::cout<<"child proc read :"<<"time: " << (unsigned)time(nullptr)<<buff<<std::endl;
       close(pipefd[0]);
    }
    pid_t ret=waitpid(id,nullptr,0);
    if(ret > 0)
    {
      std::cout<<"wait success!"<<std::endl;
      close(pipefd[1]);
    }
    
  return 0;
}

在这里插入图片描述
从时间戳的时间不难可以看出,明明是父进程休眠了5秒才进行写入操作,然而子进程却也是等待到了5秒以后才读取到对应的数据,说明管道是自带访问控制机制的! 除此之外,管道只支持单项数据。并且管道的数据也是面向字节流的!没有固定的格式,有的时候需要我们程序员手动设置数据的边界格式。

命名管道

接下来我们来讲命名管道。由于匿名管道只能作用在有血缘关系的进程之间,所以匿名管道的受限很大。因为不可 能所有的进程之间都有血缘关系。而命名管道这是能够让所有进程间进行通信的一种方式,无论这个进程是否有血缘关系。 而创建命名管道的方式有两种:

1.使用命令mkfifo + 管道权限
2.使用系统调用mkfifo创建

使用命令的方式相对比较简单,感兴趣的读者可以自行尝试。下面我们介绍使用系统接口的方式:
先来看一看手册中对于这个接口的说明:
在这里插入图片描述
下面我们就来使用以下对应的接口

//server.cc
#include<iostream>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
  int ret=mkfifo(".fifo",0666);
  if(ret < 0)
  {
    std::cerr<<"create fail"<<std::endl;
    return 1;
  }
  //创建命名管道成功
  pid_t id=fork();
  //parent
  if(id > 0)
  {
    //往管道里写入数据
    const char* msg="I am parent";
    int fd=open(".fifo",O_WRONLY);
    if(fd < 0)
    {
      std::cerr<<"open fail"<<std::endl;
      return 2;
    }
    std::cout<<"我的pid是 "<<getpid()<<" 我要往管道写入内容"<<std::endl;
    write(fd,msg,strlen(msg));
  }
  return 0;
}
//client.cc
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
  int fd=open(".fifo",O_RDONLY);
  //管道由server创建,那么client只要负责从管道里面读取数据就好了
  char buff[128];
  std::cout<<"我的进程pid是 "<<getpid()<<std::endl;
  read(fd,buff,sizeof(buff));
  std::cout<<"read from .fifo "<< buff<<std::endl;

  return 0;
}

在这里插入图片描述
可以看到:这两个进程的pid已经没有任何亲缘关系,也就是这两个进程是独立的进程了,但是server进程写入的消息确实被client进程拿到了! 这就是命名管道,实际上就是在内存中打开了一份文件,然后让不同的进程都能看到这一份文件,而剩下的操作就是正常对文件的操作了 这就是命名管道的原理

总结

1.进程间通信的本质是看到同一份资源
2.管道是进程间通信的一种方式
3.匿名管道使用系统接口pipe接口创建,pipefd[0]是读端,pipefd[1]是写端
只能用于两个有血缘关系的进程之间通信
4.命名管道使用命令mkfifo或者系统接口mkfifo,然后后面的操作全部都是文件操作

以上就是本文的主要内容,如有不足之处,还望指出。希望能够共同进步

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

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

相关文章

点云 3D 分割 - SqueezeSegV2(ICRA 2019)

点云 3D 分割 - SqueezeSegV2&#xff08;ICRA 2019&#xff09;摘要1. 引言2. 相关工作3. 改进模型结构A. 上下文聚合模块B. 焦点损失C. 其他改进4. 领域适应训练A. GTA-LiDAR数据集B. 学习强度渲染C. 测地相关对齐D. 渐进域校准5. 实验A. 实验设置B. 改进的模型结构C. 域适配…

SpringBoot与MyBatistaPlus通过jtds集成SQLServer

背景 通过 SpringBoot 与 MyBatis Plus 实现与 SQLServer 的集成&#xff0c; CRUD 。 SpringBoot集成SQLServer 新建 SpringBoot 项目&#xff0c;常规操作&#xff0c;在依赖中选择 Web , Lombok , SQLServer &#xff0c;附加 MyBatis Plus 。 核心依赖 <dependency&…

IQ基带信号

一段 IQ基带信号的解释 射频信号可以下变频得到较窄带宽的基带IQ信号&#xff0c;反之&#xff0c;较窄带的基带IQ信号可以上变频成射频信号发送。在IQ信号层面可以进行多样的调制、解调处理。 那么&#xff0c;什么是IQ信号&#xff1f; IQ信号描述推导 设调制在载波频率…

Latex基本结构和中文处理

目录源文件结构例子代码运行结果Latex中文处理办法在vscode中进行latex中文环境的编写设置步骤如下&#xff1a;在texstudio中进行中文编写步骤例子代码知识点带有序号的数学表达式用newcommand创建新的命令运行结果查看相关帮助文档ctex宏包中文版latex快速入门手册源文件结构…

力扣sql入门篇(四)

力扣sql入门篇(四) 1 丢失信息的雇员 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT e.employee_id employee_id FROM Employees e LEFT JOIN Salaries s ON e.employee_ids.employee_id WHERE s.employee_id is null UNION SELECT s.employ…

微服务框架支持

事务上下文目录概述需求&#xff1a;设计思路实现思路分析1.Seata 的事务上下文由 RootContext 来管理。2.应用可以通过 RootContext 的 API 接口来获取当前运行时的全局事务 XID。3.应用是否运行在一个全局事务的上下文中&#xff0c;就是通过 RootContext 是否绑定 XID 来判定…

机器学习--房屋销售的探索性数据分析

目录 一、导入相关包 二、读取数据 三、做简单的处理 总结 一、导入相关包 numpy&#xff1a;python中做数据分析常用的包&#xff1b; pandas&#xff1a;也是用于数据分析&#xff0c;擅长处理表&#xff0c;数据没那么大要放入内存中&#xff0c;这将是首选&#xff1…

client-go源码学习(二):Reflector、DeltaFIFO

本文基于Kubernetes v1.22.4版本进行源码学习&#xff0c;对应的client-go版本为v0.22.4 3、Informer机制 在Kubernetes系统中&#xff0c;组件之间通过HTTP协议进行通信&#xff0c;在不依赖任何中间件的情况下需要保证消息的实时性、可靠性、顺序性等。那么Kubernetes是如何…

重装操作系统win10+重装sqlserver+数据库可视化工具

sqlserver安装以及使用 一、重装操作系统 操作系统win10镜像 原因&#xff1a;sqlserver无数次失败让我放弃原来操作系统。 重装操作系统三步骤 1>下载大白菜一键装机工具 2>有一个u盘&#xff0c;8G以上存储空间 3>win10系统镜像 详细讲解&#xff1a; win10系统镜…

管道和重定向

1.重定向 1.输出重定向 > 一般用于在控制台上为了避免看到过多冗余的代码代码操作&#xff0c;所以将正确和错误的结果信息写到文件夹中 标准输出 1> 1>> [rootiZ2zef4rb5ixg6sieztgsdZ /]# cat /etc/passwd > file.txt //将/etc/passwd中输出的结果打印…

ElasticSearch6.x版本概念介绍及Kibana操作的增删改查常用API

文章目录一、概念介绍1.接近实时(NRT Near Real Time )2.索引(index)3.类型(type)4.映射(mapping)5.文档(document)6.概念关系图二、Kibana的基本操作1.创建dangdang索引并创建product类型2.删除dangdang索引3.创建id为1的文档记录4.查询id为1的文档记录5.删除id为1的文档记录6…

【2022年终总结】:小伙子还需努力呀~

文章目录前言第一次遇见CSDN我的收获我的迷茫我的展望前言 有一段时间没写博客了&#xff0c;具体什么原因呢&#xff1f;先买个关子&#xff0c;埋在下面的文字里。 眨眼时间&#xff0c;在CSDN待了快一年了&#xff0c;这一年的时间里有收获有感动&#xff0c;当然&#xff0…

IO多路复用【学习笔记】

1.用户空间和内核空间 虚拟内存被操作系统划分成两块&#xff1a;内核空间和用户空间&#xff0c;内核空间是内核代码运行的地方&#xff0c;用户空间是用户程序代码运行的地方。当进程运行在内核空间时就处于内核态&#xff0c;当进程运行在用户空间时就处于用户态。 为了安全…

elasticsearch在linux环境安装使用过程遇到的问题

es在linux环境安装遇到问题 1、启动失败日志 ERROR: [1] bootstrap checks failed [1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be con…

MCU-51:单片机之AT24C02学习

目录一、存储器介绍1.1 RAM1.2 ROM二、AT24C022.1 AT24C02介绍2.2 引脚及应用电路2.3 内部结构框图三、I2C总线3.1 I2C总线介绍3.2 I2C电路规范3.3 I2C时序结构3.4 I2C数据帧3.5 AT24C02数据帧四、代码演示4.1 AT24C02数据存储4.2 秒表(定时器扫描按键数码管)注意&#xff1a;一…

ECG信号处理——包括基本波检测、信号去噪、信号重建度量(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 心电图&#xff08;ECG&#xff09;信号自动分析与诊断是目前信号处理领域中的研究热点之一,其真正实现将有力地促进医疗事业的…

集合引用类型——对象

介绍&#xff1a; 依据变量分类&#xff1a;ECMAScript变量包括两种不同类型的值&#xff1a;原始值和引用值。 依据类型分类&#xff1a;ECMAScript类型包括两种不同类型的值&#xff1a;基本数据类型和集合数据类型。 原始值和引用值&#xff1a; 原始值就是最简单的数据&am…

网络层IP

文章目录网络层基本概念IP报头分片和组装如何分片如何组合16位标识符13位片偏移3位标志网段划分IP地址的分类CIDRIP地址数量限制私有IP和公网IP运营商路由网络层 http和tcp只考虑了两端的问题&#xff0c;并没有考虑路途中的事情。路由查找 IP的构成&#xff1a;32位网络号主…

【Ctfer训练计划】——(八)

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门 创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座…

fx5u 脉冲输出指令PLSY(DPLSY)4种写法

本文描述三菱FX5U的 脉冲输出指令PLSY(DPLSY)&#xff0c;4种写法&#xff0c;都有效。 第一行&#xff1a;设置脉冲输出频率 第二行&#xff1a;DPLSY D0 K0 K1,FX5U &#xff0c;第二个参数是脉冲数量&#xff0c;设置为K0表示一值输出脉冲。 第三个参数是轴号K1,表示Y0脉冲…