【Linux】—— 匿名管道

前言:

  • 接下来我将带大家探索 进程间通信 的方式。本期,要讲的就是管道其中之一“匿名管道”!!

目录

(一)进程间通信介绍

1、进程间通信目的

2、进程间通信发展

3、进程间通信分类

(二)管道

1、什么是管道

2、站在文件描述符角度-深度理解管道

(三)管道分类

1、匿名管道 

2、场景分类

 3、管道读写规则

4、管道特点

(四)总结


(一)进程间通信介绍

进程间通信(Inter-process communication,IPC)是指操作系统中不同进程之间进行数据交换和通信的机制

1、进程间通信目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程;
  • 资源共享:多个进程之间共享同样的资源;
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程);
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变
在一个计算机系统中,多个进程可能需要在运行时进行相互协作、共享数据或进行消息传递。为实现这些目的,操作系统提供了多种形式的进程间通信机制。

2、进程间通信发展

进程间通信(IPC)的发展一直与计算机领域的进步和需求密切相关。随着计算机技术的不断发展,IPC也经历了许多演进和改进,以满足不断增长的通信需求。以下是进程间通信发展的一些关键方面:

  • 管道
  • System V进程间通信
  • POSIX进程间通信

3、进程间通信分类

下面是几种常见的进程间通信机制:

管道
  1. 匿名管道pipe
  2. 命名管道
System V IPC
  1. System V 消息队列
  2. System V 共享内存
  3. System V 信号量
POSIX IPC
  1. 消息队列
  2. 共享内存
  3. 信号量
  4. 互斥量
  5. 条件变量
  6. 读写锁

这些进程间通信机制各有优缺点,选择合适的机制取决于应用程序的需求和特点。开发者需要考虑数据传输的速度、数据大小、并发性、可靠性等因素来选择适当的通信机制。


(二)管道

1、什么是管道

管道通信是消息传递的一种特殊方式(见下图):

  1. 所谓“管道”,是指用于连接一个读进程和一个写进程以实现它们之间的通信的一个共享文件,又名pipe文件;
  2. 向管道(共享文件)提供输入的发送进程(即写进程),以字符流形式将大量的数据送入(写)管道;而接收管道输出的接收进程(即读进程)则从管道中接收(读)数据;
  3. 为了协调双方的通信,管道机制必须提供以下三方面的协调能力:互斥、同步和确定对方的存在。

2、站在文件描述符角度-深度理解管道

【解释说明】

  • 上述描述了一个进程的默认文件符打开表,其中0、1、2是默认打开的,而3、4是分别使用读和写分别打开管道文件(当然反过来也是一样的)。

【解释说明】

  • 此时。父进程通过 fork 创建了子进程,只需把进程相关的数据结构调入,大家可以看成共享一片地址空间。

【解释说明】

  • 此时,我们关闭管道文件的读写端。就会形成一个单向通信的信道,至此双方就可以使用文件描述符对管道进行一个读一个写的操作,即实现了通信。


(三)管道分类

在Linux中,管道是一种用于进程间通信的特殊机制。根据使用方式和功能,Linux中的管道可以分为不同类型:

  1. 匿名管道(Anonymous Pipes): 匿名管道是最基本的管道类型,在命令行中使用竖线符号(|)来创建。它只能用于相关进程之间的通信,父进程与子进程之间或者同一管道链中的进程之间。

  2. 命名管道(Named Pipes): 命名管道(也称为FIFO)是一种有名字的管道,由mkfifo命令创建。它可以在磁盘上持久存在,并允许无关的进程之间进行通信。多个进程可以通过读取和写入相同的命名管道来进行数据交换。

1、匿名管道 

匿名管道是一种在进程间进行通信的机制,通常用于父子进程之间或者通过衍生的进程之间传递数据。匿名管道是一种单向通信机制,即数据只能从一个进程流向另一个进程

💨 接下来介绍匿名管道的一些关键特性:

1️⃣创建匿名管道(大家可以通过man手册进行查询)

  • 匿名管道通过系统调用(例如,在Unix/Linux中使用pipe函数)创建;
  • 创建管道时,操作系统会返回两个文件描述符,一个用于读取(读文件描述符),另一个用于写入(写文件描述符)

2️⃣下面是一个简单的C语言示例,演示了如何使用匿名管道在父子进程之间进行通信:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>#define BUFFER_SIZE 25int main() {int pipefd[2]; // 用于存放管道两端文件描述符的数组pid_t pid;char message[BUFFER_SIZE] = "Hello, child process!";// 创建管道if (pipe(pipefd) == -1) {perror("pipe");exit(EXIT_FAILURE);}// 创建子进程pid = fork();if (pid < 0) {perror("fork");exit(EXIT_FAILURE);}if (pid > 0) { // 父进程close(pipefd[0]); // 关闭用于读的文件描述符// 向管道写入消息write(pipefd[1], message, strlen(message) + 1);// 关闭用于写的文件描述符close(pipefd[1]);printf("Parent process: Message sent to child.\n");} else { // 子进程close(pipefd[1]); // 关闭用于写的文件描述符// 从管道读取消息char received_message[BUFFER_SIZE];read(pipefd[0], received_message, sizeof(received_message));// 关闭用于读的文件描述符close(pipefd[0]);printf("Child process: Received message - %s\n", received_message);}return 0;
}

2、场景分类

💨当读的一方 read 完所有的管道数据,如果写的一方不往管道里面发送数据,此时就只能等待:

 int main(){// 任何一种任何一种进程间通信中,一定要 先 保证不同的进程之间看到同一份资源int pipefd[2] = {0};//1. 创建管道int n = pipe(pipefd);if(n < 0){std::cout << "pipe error, " << errno << ": " << strerror(errno) << std::endl;return 1;}std::cout << "pipefd[0]: " << pipefd[0] << std::endl; // std::cout << "pipefd[1]: " << pipefd[1] << std::endl; // //2. 创建子进程pid_t id = fork();assert(id != -1); //正常应该用判断,我这里就断言:意料之外用if,意料之中用assertif(id == 0)    // 子进程{//3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入                                                  close(pipefd[0]);//4. 开始通信 -- 结合某种场景const std::string namestr = "hello, 我是子进程";int cnt = 1;char buffer[1024];while(true){snprintf(buffer, sizeof buffer, "%s, 计数器: %d, 我的PID: %d",namestr.c_str(), cnt++, getpid());write(pipefd[1], buffer, strlen(buffer));sleep(10);}close(pipefd[1]);exit(0);}//父进程//3. 关闭不需要的fd,让父进程进行读取,让子进程进行写入close(pipefd[1]);//4. 开始通信 -- 结合某种场景char buffer[1024];while(true){int n = read(pipefd[0], buffer, sizeof(buffer) - 1);if(n > 0){buffer[n] = '\0';std::cout << "我是父进程, child give me message: " << buffer << std::endl;}}close(pipefd[0]);return 0;}

💨当写的一方不往管道里面 write 数据,而读的一方此时不读,当管道写满之后就不能在继续写数据(即管道有大小限制):

输出结果:

 


💨当此时关闭了写数据的一方,读取完毕管道数据。如果在继续读取的话,就会 read 返回0,表明读到文件结尾。

输出结果:

 


💨当写端一直写,读端关闭,此时就没有意义,OS不会维护无意义、低效率的事件,会通过 13号 信号来杀死一直写入的进程:

输出结果:


 3、管道读写规则

🔥 当没有数据可读时:
  1. O_NONBLOCK disableread调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  2. O_NONBLOCK enableread调用返回-1errno值为EAGAIN

🔥 当管道满的时候:
  • O_NONBLOCK disable write调用阻塞,直到有进程读走数据
  • O_NONBLOCK enable:调用返回-1errno值为EAGAIN
🔥 如果所有管道写端对应的文件描述符被关闭,则read 返回 0;
🔥 如果所有管道读端对应的文件描述符被关闭,则write 操作会产生信号 SIGPIPE , 进而可能导致 write 进程退出;
🔥 当要写入的数据量不大于 PIPE_BUF 时, linux 将保证写入的原子性;
🔥 当要写入的数据量大于PIPE_BUF 时, linux 将不再保证写入的原子性。

4、管道特点

通过上述,简单总结一下管道有哪些特点:

  1. 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
  2. 管道提供流式服务 ;
  3. 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  4. 一般而言,内核会对管道操作进行同步与互斥
  5. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道


(四)总结

接下来,简单总结一下本期关于“匿名管道”的全部知识!!!

  1. 使用匿名管道可以方便地在父子进程之间传递数据,但也有一些限制,如只能用于具有亲缘关系的进程间通信,无法用于无关进程之间的通信;
  2. 此外,管道的容量有限,如果写入速度超过读取速度,可能会导致阻塞;
  3. 在实际使用中,可以根据需求选择其他更复杂的进程间通信机制,如命名管道、共享内存或消息队列等。

以上便是本期关于匿名管道的全部内容了,感谢大家的观看与支持!!!

 

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

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

相关文章

文件分片上传(模拟网盘效果)

文件分片上传&#xff08;模拟网盘效果&#xff09; 文章说明简单模拟拖拽文件夹和选择文件的进度条效果效果展示结合后端实现文件上传效果展示加上分片的效果效果展示加上MD5的校验&#xff0c;实现秒传和分片的效果后续开发说明源码下载 文章说明 文章主要为了学习文件上传&a…

2024年【黑龙江省安全员C证】考试及黑龙江省安全员C证找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年黑龙江省安全员C证考试为正在备考黑龙江省安全员C证操作证的学员准备的理论考试专题&#xff0c;每个月更新的黑龙江省安全员C证找解析祝您顺利通过黑龙江省安全员C证考试。 1、【多选题】下列属于编制安全检查…

浅聊配置化-要不要实现动态表单

1、配置化的原则 配置化是一种抽象&#xff0c;把事物分成2类&#xff1a;不变的&#xff0c;可变的。 如果事物都是可变的&#xff0c;是无法实现配置化的。 配置化的根本在于找到不变的事物&#xff0c;基于不变的事物进行可变事物的配置。 所以&#xff0c;认为一切皆可…

[LLM]大模型训练(二)--DeepSpeed使用

安装DeepSpeed与集成 DeepSpeed可以通过pip安装&#xff0c;无需指定PyTorch和CUDA的版本。DeepSpeed内包含需要自定义的CUDA算子&#xff0c;将通过即时编译的方式在运行时构建。 pip install deepspeed DeepSpeed与HuggingFace Transformers直接集成。使用者可以通过在模型…

从入门到精通,30天带你学会C++【第十一天:二分查找】

目录 Everyday English 前言 二分查找 例题 50分做法 分析利弊 示例代码 示例截图 100分做法 二分查找是什么&#xff1f; 这题该怎么用二分查找&#xff1f; 示例代码 示例截图 结尾 Everyday English Look before you leap. 三思而后行 前言 今天是2024年的…

爬取糖豆视频

爬虫案例积累&#xff0c;以爬取糖豆视频为例&#xff1a; 爬取视频类型的数据一般步骤&#xff1a; 1.点击media,刷新&#xff0c;播放一个视频&#xff0c;会刷新一个包&#xff0c;点击发现是播放视频的包&#xff0c; 2.复制这个包url中的关键字&#xff0c;在搜索框中进…

在宝塔Linux中安装Docker

前言 帮助使用宝塔的用户快速上手docke的安装 &#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Docker》。&#x1f3af;&#x1f3af…

[新版Hi3531DV200 性能强悍]

新版Hi3531DV200 性能强悍 Hi3531DV200是针对多路高清/超高清&#xff08;1080p/4M/5M/4K&#xff09;DVR产品应用开发的新一代专业SoC芯片。Hi3531DV200集成了ARM A53四核处理器和性能强大的神经网络推理引擎&#xff0c;支持多种智能算法应用。同时&#xff0c;Hi3531DV200还…

Spring Boot Admin健康检查引起的Spring Boot服务假死

问题现象 最近在spring boot项目中引入了 spring-boot-starter-actuator 后&#xff0c;测试环境开始出现服务假死的现象&#xff0c; 且这个问题十分怪异&#xff0c;只在多个微服务中的简称A的这个服务中出现&#xff0c;其他服务都没有出现这个问题&#xff0c; 之所以说…

按照故障码类型分类的API接口

随着汽车的普及&#xff0c;车辆故障也成为了一个不可忽视的问题。对于车主来说&#xff0c;及时了解故障码的含义以及解决方案十分重要。挖数据平台为解决这一问题&#xff0c;提供了一套按照故障码类型分类的API接口&#xff0c;用于查询车辆故障、故障码适用品牌以及提供相应…

STL——queue容器

1.queue基本概念 概念&#xff1a;queue是一种先进先出&#xff08;First In First Out,FIFO&#xff09;的数据结构&#xff0c;它有两个出口。 队列容器允许从一端新增元素&#xff0c;从另一端移除元素。 队列中只有队头和队尾才可以被外界使用&#xff0c;因此队列不允许…

Java API 操作Docker浅谈

背景&#xff1a; 使用com.github.docker-java库可以很方便地在Java中操作Docker。下面是一个详细的教程&#xff0c;包括创建镜像、创建容器、启动容器、停止容器和删除容器的步骤以及每一步的说明。 前提&#xff1a; 首先&#xff0c;在你的Java项目中添加com.github.doc…

Linux之组管理和权限管理

组的概念 如图所示&#xff1a;test.txt是由tom创建的&#xff0c;所以tom是文件的所有者&#xff0c;tom归属于组A&#xff0c;组A就是文件的所在组&#xff1b;组B就是文件的其他组。 所有者 谁创建了文件&#xff0c;谁就是文件的所有者。 查看文件的所有者 指令&…

Django 学习教程- Hello world入门案例

系列 Django 学习教程-介绍与安装-CSDN博客 欢迎来到第Djagno学习教程第二章Hello World 入门案例。 在本教程中&#xff0c;我将引导您完成django的Hello World入门案例。 让我们开始吧&#xff01; 版本 Django 5.0Python 3.10 创建项目 安装 Django 之后&#xff0…

信创之国产浪潮电脑+统信UOS Linux操作系统体验10:visual studio code中调试C++程序

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、引言 老猿在CSDN的《信创之国产浪潮电脑统信UOS操作系统体验2&#xff1a;安装visual studio code和cmake搭建C开发环镜》介绍了在国产浪潮电脑统信UOS操作系统中安装visual studio code和cmake搭建C开…

css动态传参,attr的妙用

今天再做一个编辑器的功能的时候&#xff0c;发现有一段非常奇妙的代码&#xff0c;使用attr获取div标签的data-label值。 css的attr?What fuck?这又是什么鬼东西&#xff0c;emmm。 查询后官方是这么回答的&#xff1a; CSS 表达式 attr() 用来获取选择到的元素的某一 HTM…

GO语言基础笔记(八):高级特性与性能优化

目录 反射&#xff08;Reflection&#xff09; 反射概念 反射的关键概念 反射的常见用途 代码示例 1. 检查类型和值 2. 修改变量值 3. 调用函数 4. 结构体反射 并发模式&#xff08;Concurrency Patterns&#xff09; 1. Worker Pool 模式 工作原理 在代码中的体现…

Unity坦克大战开发全流程——结束场景——通关界面

结束场景——通关界面 就照着这样来拼 写代码 hideme不要忘了 修改上一节课中的代码

动态内存管理篇

为什么要动态内存分配&#xff1f; 之前&#xff0c;我们向内存申请空间&#xff0c;有两种方式&#xff0c;一种是定义变量&#xff0c;一种是建立数组&#xff1b;但是&#xff0c;这两种方式都有缺陷&#xff0c;创建的空间大小是固定的&#xff0c;在程序的运行过程中&…

买对好车省钱又防坑,高性价比的买车攻略

一、教程描述 正所谓隔行如隔山&#xff0c;买车这件事情并不简单&#xff0c;买车的内幕还是有不少的&#xff0c;本套教程讲述买车攻略&#xff0c;非常适合准备买车的朋友&#xff0c;可以帮助大家买车少入坑&#xff0c;高性价比买到自己心仪的车。本套买车教程&#xff0…