进程间通信之管道篇

news2024/11/28 5:44:35

🏆一、进程间通信目的

1.1什么是通信

进程是具有独立性的,而我们要实现进程间通信的目标,是需要开辟空间和创造方法的。

通信目的:

1、数据传输:一个进程需要将它的数据发送给另一个进程

2、资源共享:多个进程之间共享相同的资源。

3、通知事件:一个进程需要向另一个或一组进程发送消息(例如进程终止要通知父进程)

4、进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

那么管道就是十分传统的一种解决进程间通信的方式。

在学习进程间通信之前,我们就曾见识过管道的使用。

 

进程通信的原因:多进程协同完成某项任务

目前主要的进程间通信的方式有三种:POSIX(让通信过程可以跨主机) ,System V(聚焦在本地通信,主要有共享内存,消息队列,信号量),以及管道(依托于文件系统完成的一套技术方案)

🏆二、匿名管道

2.1匿名管道的由来

说了这么多,那么管道到底是什么?管道的底层原理是什么?我们如何创建和通过管道来实现进程间通信呢?

匿名管道是基于父子进程而衍生的一种解决方案

 父进程打开一个文件后,通过fork()创建子进程,子进程继承父进程文件描述符表,这样两个进程就指向了同一个文件。

父进程通过打开的这个文件的缓冲区写入,子进程再从缓冲区读取,这种过程就是一个进程向文件当中写数据,另一个进程从文件当中读数据。这样进程间就实现了数据传输,而这个过程就是进程间通信

这里还有一个问题,这个文件是否需要向磁盘写数据和读取数据呢?

答案是不需要!因为我们这个文件是供父子进程之间进行通信使用,而非存储到磁盘。而IO的过程是非常影响效率的。正因为它有这一特性也就意味着它和一般的文件是不同的。没错,它是由OS提供的内核级文件--->匿名管道。

管道文件和普通文件的区别:

2.2基于匿名管道再理解进程间通信

首先必须得有两个进程都能看到的部分,因为两个进程都能从公共部分写入或读取才能实现数据传输。又因为进程具有独立性,所以我们进程间要实现通信,必须由第三方提供缓冲区供进程间进行数据传输。如果由A进程提供缓冲区会因为进程的独立性导致A进程独有,B进程与之同理。所以第三方必然是操作系统(OS).

1、OS需要直接或间接给通信双方的进程提供内存空间。

2、要通信的进程必须看到一份公共的资源。

这一原理贯穿了所有的进程间通信实现方案:

所谓的不同的通信种类本质就是让进程间看到同一份资源,这份资源是OS哪一模块提供的,就是什么通信模式

2.3匿名管道的使用

从上图我们看到,父进程先创建管道文件,父进程有管道文件的读写端,然后fork创建子进程,这样由于子进程继承父进程的文件描述符表,所以子进程也有管道的读写端。然后父进程关闭读端/写端,子进程关闭写端/读端。通过管道就能实现单向进程通信

那么为什么父进程不关闭读端或写端后再fork()创建子进程呢?

因为父子进程关闭的读写端不一样,如果父进程关闭读端,那么子进程继承的也是关闭读端;而父进程需要读端是开启的(否则无法实现单向通信)。所以是创建完子进程后再关闭读端/写端。

 

OS提供的管道的接口,调用成功返回0.调用失败返回-1.

参数pipefd[2]是输出型参数,调用pipe接口的时候,OS以读和写的方式打开文件,并将读和写对应的文件描述符下标填到pipefd数组中。通过数组,把读端和写端对应的下标全部返回。就以读和写的方式打开了pipe文件。

演示:

 那么输出型参数返回的数组中fds[0]fds[1]谁是读取,谁是写入呢?

2.4演示使用匿名管道

 

我们如何验证我们的管道成功通信了呢?因为我们的子进程给父进程发的消息有自己的pid,而我们在父进程打印接收到的消息时,打印了父进程的pid。所以我们只需监控查看进程pid,与我们打印出的内容进行对照即可验证是否完成管道通信。

 

经验证,确实完成了进程间通信。

匿名管道的实际通信过程:

2.5匿名管道的几种情境下的特点

①写端慢,读端快

这句话是什么意思呢?这是一种场景,让写端输入慢(写端会sleep),而读端不设限制。比如写端(子进程)在sleep期间,父进程在做什么呢?

父进程在等待读取,首先read方法是一种阻塞式调用当写端没有写入信息时,读端在等待读取,而非执行循环

我们可以验证一下:将子进程(写端)代码改为在写入数据后,休眠50s

再来看父进程(读端)会有何表现:

 

我们可以看到,在读取过一次后,由于写端没有输入而是在sleep。读端就阻塞在read,等待读取。(如果是执行循环就应该打印"bbbbbbbbb"而非阻塞)

这里我们发现,如果管道中没有了数据,读端再读,默认会直接阻塞当前正在读取的进程!

② 写端快,读端慢

与上一种情境相反,我们让子进程循环写入,而父进程读取端sleep。

 发现会一瞬间写满pipe文件。写满后就不会再写了,此时写端就会被阻塞。

当写端快,读端慢的时候会写满管道文件,然后写端阻塞等待读端读取。

③写端先于读端关闭

如果我们写一条信息,子进程就关闭写端fd。作为读端(父进程),如果写端已经关闭,而读端已经全部读取管道文件中的数据,那么读端就会读到文件结尾。

 子进程(写端)关闭,父进程读到返回值0,读端读到写端关闭结果。

④读端先于写端关闭

如果读端关闭,那么写端写的数据将不会被接收,也就是说写端写的数据将没有任何意义。

那么此时OS会自动终止写端,会给写端进程发送信号,终止写端。

 

 我们看到子进程pid是32134,收到的终止信号是13号。那么13信号是什么意义呢?

此时我们可以总结匿名管道的四种情况和五大特征

四种情况:

1、写端慢,读端快。读端不会循环而是阻塞在read方法,等待写端写入数据读取。

2、读端慢,写端快。写端写满管道文件,就不再写入数据,等待读端读取数据。

3、写端先于读端关闭。读端会先把管道中的数据全部读取后,读取到写端退出返回的结果,从而关闭读端,不再读取。 

4、读端先于写端关闭。读端关闭,写端写入的数据不被接收,就没有了意义。OS会自动终止写端,会给写端进程发送信号,终止写端。

五大特征:

1、只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

2、管道是面向字节流的。

3、一般而言,进程退出,管道释放,所以管道的生命周期随进程。

4、内核会对管道操作进行同步和互斥。通俗点讲就是任何一个时刻,只允许一个进程向另一个进程发送消息。(涉及到加锁,等到多线程部分再说)

5、管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。

🏆三、匿名管道的应用

在了解了匿名管道后,我们可以做一个小游戏。原理很简单:父进程通过管道给子进程发送一个命令操作码,子进程根据命令操作码执行对应的任务。为了提高效率我们要创建多个子进程,并且随机给每个子进程发送命令操作码,避免某个子进程执行过多任务。

上面即是原理图。

 

 上图就是我们简单实现的一个程序。

我们运行查看一下:

我们看到代码成功执行:父进程随机挑选一个任务,将其任务码(这里转换成指针数组的下标)发送给随机一个子进程,子进程接收到任务后,执行对应的操作!

而我们实现的代码,复用性很强,耦合度低,想执行其他任务,只需改动实现函数即可。

但是我们写的代码有一个很深的bug

父进程打开的文件,是会被子进程共享的!

 

 

如何解决这个问题呢?除了我们之前的暴力关闭所有的写端。我们还可以保存fork() 继承下来的没必要的写端到一个vector容器中,每次对子进程操作时,关闭继承下来的写端:

 🏆四、命名管道

4.1命名管道

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道命名管道是一种特殊类型的文件。

mkfifo是创建管道文件的命令。

这里以p开头的文件叫做管道文件它的作用在于使两个不相关的进程一个可以向它写入,一个向它读取,直接完成进程间通信

 

我们看到确实写入了数据,但是为什么管道文件的大小是0呢?这是因为它不把数据刷新到磁盘上,所以看到的是0.

我们已经有一份公共的资源以供读取,匿名管道是通过继承的方式让父子进程看到同一个文件, 那么命名管道是如何做到让不同的进程看到同一份资源呢?

只需让不同的进程打开指定路径(路径+文件名)的同一个文件就可以了

4.2命名管道的使用

上面是指令级别的使用,我们编写代码时,操作系统提供有专门的接口。

 

我们运行一下上述代码:

 

成功创建管道文件。

那么我们不想要这个管道文件时,可以通过unlink接口。

 

 这段代码是由client通过命名管道named_pipeserver写数据。

但是我们还需要注意几个细节:

1、当server运行打开命名管道,它会等待client同样打开相同管道文件后再向后运行。

 

 2、为什么server端会多出一个换行符呢?

这是因为我们的回车键也被读取了!

我们需要手动去除:

 4.3匿名管道和命名管道的区别

·匿名管道由pipe函数创建并打开。

·命名管道由mkfifo函数创建,打开用open

·FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在他们创建与打开的方式不同,一旦这些工作完成之后,它们具有相同的语义。

·命名管道使用的前提是双方必须都打开它(一个以读的形式,一个以写的形式),否则就会阻塞

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

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

相关文章

CSAPP 第六章存储器的结构层次

源程序 执行程序 空间代码都要存在外存上,程序运行的时候操作系统要把外存的东西加载到内存里,CPU要从内存一行一行的读、译码和分析 我们来看一个例子: 指令位于内存中的代码段中,必须从内存中读出来进行译码分析之后才能运行 指…

细说java动态代理及使用场景

一、定义 Java代理模式是一种结构型设计模式,它允许通过创建一个代理对象来间接访问另一个对象,从而控制对原始对象的访问。 1.1 作用 1、在访问原始对象时增加额外功能,如访问前或访问后添加一些额外的行为。 2、控制对原始对象的访问。 J…

热水智能控制系统有什么优点?

热水智能控制系统是一种先进的技术,可以极大地提高家庭和商业场所的热水使用效率,降低能源消耗和运营成本。这种系统利用现代化的传感器、控制器和通讯技术,可以智能地监测和控制热水的温度、流量和使用情况,并根据实际需求来调节…

ASEMI代理ADI亚德诺ADM706SARZ-REEL原厂芯片

编辑-Z ADM706SARZ-REEL参数描述: 型号:ADM706SARZ-REEL VCC工作电压范围:1.0-5.5V 电源电流:100μA 重置阈值滞后:20 mV 复位脉冲宽度:200 ms PFI输入阈值:1.25V PFI输入电流&#xff…

Linux 部署 scrapydweb

一、 创建虚拟环境,在虚拟环境下操作 1、安装scrapyd pip install scrapyd2、安装scrapyd-client pip install scrapyd-client3、安装scrapydweb pip install scrapydweb4、安装Logparser pip install Logparser二、新建一个scracyd的配置文件 sudo mkdir /etc/scr…

MySql.Data.dll 因版本问题造成报错的处理

NetCore 链接MySQL 报 Character set ‘utf8mb3‘ is not supported by .Net Framework 异常解决_character set utf8mb3_csdn_aspnet的博客-CSDN博客 查看mysql版本号,两种办法: 第一种在数据库中执行查询:SELECT version; 第二种使用工具…

数据治理和合规性:如何确保大数据应用遵守法规和标准

第一章:引言 在数字时代,大数据的应用日益普遍,对企业和组织的决策、运营和创新产生了深远的影响。然而,随着数据规模的不断增长,以及数据泄露和滥用事件的频繁发生,数据治理和合规性问题愈发突显。企业和…

推荐系统用户长序列建模

目录 一、背景 二、技术方案 2.1 DIN 简介 论文细节 优缺点 2.2 DINE 简介 论文细节 2.3 MIMN 简介 论文细节 2.4 SIM 简介 论文细节 优缺点 2.5 DSIN 简介 论文细节 一、背景 阿里巴巴的精排模型从传统lr,到深度学习,再到对用户长历…

使用云服务器可以做什么?十大使用场景举例说明

使用阿里云服务器可以做什么?阿里云百科分享使用阿里云服务器常用的十大使用场景,说是十大场景实际上用途有很多,阿里云百科分享常见的云服务器使用场景,如本地搭建ChatGPT、个人网站或博客、运维测试、学习Linux、跑Python、小程…

6年测试,不断磨炼升级打怪自动化测试,一路晋升他终于冲出月35k+

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Python自动化测试&…

ViT 论文逐段精读

https://www.bilibili.com/video/BV15P4y137jb Vision Transformer 挑战了 CNN 在 CV 中绝对的统治地位。Vision Transformer 得出的结论是如果在足够多的数据上做预训练,在不依赖 CNN 的基础上,直接用自然语言上的 Transformer 也能 CV 问题解决得很好…

如何学习web前端开发?这样学前端事半功倍,能救一个是一个!

非常理解想要自学前端的伙伴,因为好程序员的学员一开始也是自学插画的,很多同学,自学到最后真的非常枯燥乏味,且走了很多弯路。小源想着能帮一把是一把的原则,这两天整理了一份前端的高效学习路线,想学web前…

接口测试常用工具及测试方法(基础篇)

首先,什么是接口呢? 接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口。 系统对外的接口:比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把数据库共享给你,他只能给…

Windows管理内存的3种方式——堆、虚拟内存、共享内存

一、操作系统管理内存概述 在 Windows 操作系统中,每个进程都被分配了 4GB 的虚拟地址空间,这被称为进程的虚拟地址空间。虚拟地址空间提供了一个抽象的地址空间,使得每个进程都可以认为它拥有自己的独立内存空间。这个虚拟地址空间被分为两…

720度沉浸式体验,VR虚拟展馆的价值有哪些?

展馆作为一个展示商品、会议交流、信息传播、经济贸易的场所,能够创造巨大的经济效益和社会效益。什么是VR虚拟展馆呢?VR虚拟展馆是基于VR全景技术打造的线上展厅,可以应用在多种领域中展示各式的商品和内容,观众通过VR虚拟展馆可…

ubuntu系统下使用ros控制UR真实机械臂,逻辑清晰,亲测有效

梳理一下在ubuntu系统使用ros控制UR真实机械臂的思路,逻辑清晰,亲测有效,并记录踩过的坑。从0开始,使用ros控制真实UR机械臂。 环境:ubuntu18.04 ros版本:melodic 机械臂型号:UR5e 一&#xff…

当我与单链表分手后,在酒吧邂逅了双向循环链表.....

链表的种类有8种,但我们最常用的为无头单向非循环链表和带头双向循环链表。 带头双向循环链表 当带头双向循环链表只有哨兵位头的时候,双向链表的指向如下图。 head->pre和head->next都是指向自己,这个是有巨大优势的,代码…

CTFHub | 文件包含

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习,实训平台。提供优质的赛事及学习服务,拥有完善的题目环境及配套 writeup ,降低 CTF 学习入门门槛,快速帮助选手成长,跟随主流比赛潮流。 0x01 题目描述…

一篇文章让你上手Canal数据同步神技~

视频教程传送门: Canal极简入门:一小时让你快速上手Canal数据同步神技~_哔哩哔哩_bilibiliCanal极简入门:一小时让你快速上手Canal数据同步神技~共计13条视频,包括:01.课前导学与前置知识点、02.Canal组件了解、03.My…

光纤收发器可以连接光模块吗?

随着科技的进步发展,城市信息化速度的加快,光通信产品在数据中心和安防监控等场景中的运用越来越广泛,而这之间的连接则需要光模块和光纤收发器来实现。很多用户对光模块和光纤收发器的使用有些疑虑,两者该如何连接?又…