Linux学习记录——십구 构建进程间通信的信道方案

news2025/7/19 11:23:42

文章目录

  • 1、进程间通信介绍
    • 1、目的
    • 2、发展
  • 2、管道
    • 1、原理
    • 2、简单模拟实现
    • 3、总结
  • 3、匿名管道——控制进程
  • 4、命名管道
    • 1、原理
    • 2、模拟实现


1、进程间通信介绍

之前所学都是单个进程,多个进程之间如何运转?

1、目的

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止
时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另
一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程是有独立性的,这增加了通信的成本。要让两个不同的进程进行通信的前提条件就是让两个进程看到同一份资源。这是操作系统直接或间接提供的。

对于任何通信手段,都要先让不同的进程看到同一份资源,然后一方写入,一方读取来完成通信。

2、发展

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

2、管道

1、原理

管道是Unix中最古老的进程间通信的形式。

我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

可以同时创建多个进程,通过管道连接,它们的父进程也都一样,bash。

管道也是文件,一个文件以写方式打开管道,将自己的标准输出重定向到管道,另一头的文件以读方式打开管道,将自己的标准输入重定向到管道。

文件进程开始时,结构体里有文件描述符的表,指向各个文件,除此之外,还会打开一个匿名管道,这是一个操作系统提供的纯粹的内存文件,不需要刷新内容到磁盘。通过进程调用,这个匿名管道会通过读和写打开同一个文件;当前进程会fork一下,把自己的文件描述符表拷贝给子进程,具体的内容会有对应更改,那打开的文件等需要拷贝吗?不拷贝。但没关系,因为文件描述表的原因,子进程依然指向父进程创建好的文件,包含那个匿名管道。这其实也相当于一个浅拷贝。父子进程指向的文件一样。所以父子都指向那个匿名管道,一方更改,一方就能得到新数据;不过这时候管道只支持单向通信,接下来要做的是确定数据流向,关闭不需要的fd。操作系统会把子进程的写方式和父进程的读方式都关掉,这样父写子读,就形成了一个管道。

管道确实只能单向通信,如果想要双向,就定义两个管道。

2、简单模拟实现

简单的代码,子进程向父进程发消息,就是一种管道。

 10 int main()
 11 {
 12     int pipefd[2] = {0};
 13     //1、创建管道
 14     int n = pipe(pipefd);
 15     if(n < 0)
 16     {
 17         std::cout << "pipe error, " << errno << ":" << strerror(errno) << std::endl;
 18         return 1;
 19     }
 20     std::cout << "pipefd[0]: " << pipefd[0] << std::endl;
 21     std::cout << "pipefd[1]: " << pipefd[0] << std::endl;
 22     //2、创建子进程
 23     pid_t id = fork();
 24     assert(id != -1);
 25     if(id == 0)
 26     {
 27         //3、关闭不需要的fd,让父进程进行读取,让子进程进行写入
 28         close(pipefd[0]);
 29         //4、开始通信
 30         const std::string namestr = "hello, 我是子进程";
 31         int cnt = 1;
 32         char buffer[1024];
 33         while(true)
 34         {
 35             snprintf(buffer, sizeof(buffer), "%s, 计数器: %d, 我的PID: %d\n", namestr.c_str(), cnt++, getpid());
 36             write(pipefd[1], buffer, strlen(buffer));
 37             sleep(1);
 38         }
 39         close(pipefd[1]);
 40         exit(0);
 41     }
 42     //父进程
 43     //3、关闭不需要的fd
 44     close(pipefd[1]);
 45     //4、开始通信
 46     char buffer[1024];
 47     while(true)
 48     {
 49         int n = read(pipefd[0], buffer, sizeof(buffer) - 1);                                                                                                                                                  
 50         if(n > 0)
 51         {
 52             buffer[n] = '\0';
 53             std::cout << "我是父进程,child give me message: " << buffer << std::endl;
 54         }
 55     }
 56     close(pipefd[0]);
 57     return 0;
 58 }

链接: https://gitee.com/kongqizyd/linux-beginner/tree/master/pipe

3、总结

特点

1、单向通信,一种半双工,意思为双方交替着工作;全双工则是双方可以同时工作
2、管道本质是文件,因为文件描述符和文件的生命周期随进程,所以管道的生命周期也随进程。父子进程退出,那么之前关掉的文件描述符又会回到之前的位置
3、父子进程能够通信也是有继承存在于其中的。管道通信通常用于具有“血缘”关系的进程,常用于父子进程。兄弟进程之间也可以通信。pipe打开管道时不需要关心打开了哪个文件,只要得到两个文件描述符就好,因为pipe打开的匿名管道
4、管道通信中,写入的次数和读取的次数不是严格匹配的,可能读了7个但是只读了1次把它们都读取了。读写没有强相关。读取是面向字节流的,读取只看应读的字节数
5、管道具有一定的协同能力,让读和写能按照一定的步骤进行通信----自带同步机制

场景

1、如果我们read读取完了所有的管道数据,对方不写入,读取方只能等待
2、write端写满后(一般是65535/65536,大约是64kb),就不会继续写了,等到读端读取。可以在子进程那里不写sleep,而父进程sleep(10),看实际现象
3、如果关闭了写端,读取完管道数据,再读就会返回0,表明读到了文件结尾
4、写端一直写,读端关闭,那么写入就变得没有意义;操作系统不会维护无意义,低效率,浪费资源的进程,所以进程会直接杀掉这个进程。系统会通过信号来终止进程,SIGPIPE -13关闭进程

3、匿名管道——控制进程

父进程可以通过向子进程写入特定的消息,唤醒子进程,甚至让子进程定向的执行某种任务。父进程可以打开多个管道和子进程连接。父进程对自己创建的管道和进程会先描述再组织。

子进程在创建时会继承父进程的文件描述符,所以第一个父进程会有好多个子进程连接到它,这就混乱了。实际要实现的结构是一对一,一对父子进程间有自己独立的管道,而不受其他进程影响。

链接: https://gitee.com/kongqizyd/linux-beginner/tree/master/ctrlProcess

4、命名管道

匿名管道有局限性,只能用于有血缘关系的进程之间进行通信,要让两个陌生的进程之间通信就需要用到命名管道。

创建命名管道要用到mkfifo命令,括号里就是命名管道参数,fifo意思就是先进先出

在这里插入图片描述

它的文件类型以p开头,说明是一个管道文件。

现在写个命令echo “字符串” >fifo,往这里面写内容,但是光标会停在下一行开头,一直闪烁,这是因为fifo文件只是一个符号,向里面写的东西不会真实存在在磁盘中,只写到管道文件中,我们可以用cat命名读,它默认从显示器读,cat < fifo就会从管道文件读,然后打印到显示器上。即使写一个一直输出内容的代码,也可以另开一个窗口用cat来获取内容。

1、原理

在之前基础IO博客中的硬链接部分写到过引用计数这个东西,命名管道里也会用到引用计数。在磁盘中的一个文件,如果不打开,就待在磁盘里;打开后就会有自己的文件结构体,里面有各项参数,其中就有引用计数;操作者创建进程后,会有文件描述符表等东西,进程可以打开在内存中的文件,此时引用计数就变成了1;如果再开一个进程,打开同样的文件,系统不会在开一个这个文件的结构体,而是这两个进程指向同一个文件结构体,计数变为2,进程一个个消失,计数就从2变为0。但两个进程如何保证打开同一个文件,要想让文件唯一,文件路径+文件名都相同就可以。

2、模拟实现

创建管道文件,让读写端进程分别按照自己的需求打开文件,然后开始通信。

在这里插入图片描述

我们定义两个文件,要形成两个可执行程序需要这样写。

在这里插入图片描述

链接: https://gitee.com/kongqizyd/linux-beginner/tree/master/namepipe

结束。

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

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

相关文章

SpringSecurity之基本原理——过滤器链

前言 前面我们讲解了入门案例&#xff0c;很多小伙伴看完之后&#xff0c;应该也不知道他是如何实现的拦截。接下来&#xff0c;我们看一下SpringSecurity的基本原理是什么&#xff1f; 本质 其实&#xff0c;SpringSecurity的本质上就是一个过滤器链。在启动时&#xff0c;…

我的面试八股(JVM篇)

谈一谈Java内存区域和Java内存模型的理解&#xff1f; / Java内存区域和Java内存模型是一个东西吗&#xff1f; Java内存区域和Java内存模型不是一个东西&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; Java内存区域&#xff0c;也就是Java运行时数据区域。是…

Typora自定义主题分享 (Mac风、图片立体感...)

MarkDown 主题分享 文章目录MarkDown 主题分享Ligth-浅色主题主题效果展示安装方式Dark-深色主题主题效果展示安装方式关键字&#xff1a;Typora 、Mac、图片阴影、代码样式、表格 Ligth-浅色主题 主题效果展示 安装方式 下载 Typora 官网 Mo主题 下载地址将Mo.css样式修改为…

Docker容器部署

Docker容器1.Docker概念1.1.什么是Docker1.1.1.应用部署的环境问题1.1.2.Docker解决依赖兼容问题1.1.3.Docker解决操作系统环境差异1.1.4.小结1.2.Docker和虚拟机的区别1.3.Docker架构1.3.1.镜像和容器1.3.2.DockerHub1.3.3.Docker架构1.3.4.小结1.4.安装Docker2.Docker的基本操…

【无人机】采用最基本的自由空间路损模型并且不考虑小尺度衰落(多径多普勒)固定翼无人机轨迹规划(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

每日刷题记录(十四)

目录第一题&#xff1a;子集解题思路&#xff1a;代码实现&#xff1a;第二题&#xff1a;组合解题思路&#xff1a;代码实现&#xff1a;第三题&#xff1a;全排列解题思路&#xff1a;代码实现&#xff1a;第四题&#xff1a;全排列II解题思路&#xff1a;代码实现&#xff1…

2023年4月传统行业产品经理需要考NPDP吗?含金量高吗?

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

Linux内存管理(七):fixmap详解

源码基于:Linux 5.4 约定: 芯片架构:ARM64 CONFIG_ARM64_VA_BITS:39 CONFIG_ARM64_PAGE_SHIFT:12 0. 前言 内核启动首先会进入汇编阶段,mmu已经启动 (也就是说,当前SOC只能使用虚拟地址访问RAM),paging_init还没有完成调用,在内核启动过程需要访问某些特定的内核模…

SQL综合查询上

目录1、查询输出“高等数学”课程成绩前三名&#xff08;不考虑成绩有重复值的情况&#xff09;的学生的学号&#xff0c;姓名&#xff0c;课程名&#xff0c;系名&#xff0c;成绩。题目代码2、统计各门课程的重修人数&#xff08;包括grade为NULL&#xff09;&#xff0c;要求…

体验了一把ChatGPT4

不得不说ChatGPT对我的学习效率有极大的提升&#xff0c;它就像一位老师&#xff0c;不管有什么问题&#xff0c;都可以得到很好的答案。但是前段时间gpt3.5账号被封了&#xff0c;最近搞了个gpt4。市面上目前好像没啥可以白嫖的账号&#xff0c;基本都是免费使用几次&#xff…

C++11新特性有效总结

目录 语言可用性加强 (读现代C教程有感) nullptr constexpr if/switch 申明强化 &#xff08;C17开始&#xff09; 初始化参数列表 范围for迭代 两种类型推导方式 变长参数模板 SmartPointer Lambda 多线程 (并发与并行) 并发与并行的概念 C11中的并发并行 软件…

基于单片机的温室大棚环境监测系统设计

温室大棚对北方反季节蔬菜的种植具有重要意义。据了解全国各地温室大棚使用集中&#xff0c;但是大棚环境调控方式落后、管理落后、生产效率比较低。针对此问题本文提出了一种基于STM32单片机智能温室大棚控制系统方案&#xff0c;实现环境参数的自动检测&#xff0c;以达到智能…

C语言从入门到精通第2天(深度解析C语言数据类型及取值范围)

C语言基本数据类型及取值范围数据存储概述基本数据类型整型数的二进制表示浮点型数的二进制表示取值范围数据存储概述 C语言的变量有着不同的数据类型&#xff0c;每种数据类型的取值空间都是不同的&#xff0c;因此&#xff0c;不同数据类型的变量&#xff0c;其取值空间也不…

利用注解和反射解决代码冗余问题(改进版)

在优化代码的时候发现&#xff0c;传参存在着高度冗余&#xff0c;如果后面需要改参数&#xff0c;很不方便。 String pam1 "id" appKey "&sign" sign "&method" method "&access_token" token "&times…

光隔离器的工作原理及其应用

光隔离器也称为光隔离器或光耦合器&#xff0c;它是一种通过使用光将电信号或电压从一个电路传输到另一个电路的装置&#xff0c;同时它将两个电路彼此隔离。它可以通过隔离过压信号来防止高电压或快速变化的电压损坏组件。光隔离器可以承受高达10KV的输入至输出电压和高达10KV…

html+css+JavaScript+json+servlet的社区系统(手把手教学)

目录 课前导读&#xff1a; 一、系统前期准备 二、前端代码的编写 三、登陆页面简介 四、注册页面 五、社区列表页 六、社区详情页 七、社区发帖页 八、注销 九、访问链接 登陆页面http://175.178.20.77:8080/java106_blog_system/login.html 总结&#xff1a; 课前…

HTML5 <embed> 标签、HTML5 <figcaption> 标签

HTML5 <embed> 标签 实例 被嵌入的 flash 动画片&#xff1a; <embed src"helloworld.swf">尝试一下 浏览器支持 注意: 大多数现代浏览器已经弃用并取消了对浏览器插件的支持&#xff0c;所以如果您希望您的网站可以在普通用户的浏览器上运行&#xf…

【SpringCloud系列】开发环境下重写Loadbalancer实现自定义负载均衡

前言 spring-cloud-starter-netflix-ribbon已经不再更新了&#xff0c;最新版本是2.2.10.RELEASE&#xff0c;最后更新时间是2021年11月18日&#xff0c;详细信息可以看maven官方仓库&#xff1a;https://search.maven.org/artifact/org.springframework.cloud/spring-cloud-st…

【计算机图形学】裁剪算法(逐边裁剪法 Weiler-Atherton裁剪法)

一 实验目的 编写直线段、多边形裁剪算法熟悉逐边裁剪法、Weiler-Atherton裁剪法的使用 4&#xff1a;用逐边裁剪法实现多边形裁剪&#xff08;代码最上方功能区注明是否处理退化边&#xff09; 无退化实验结果如下图所示&#xff1a; 图形初始化&#xff1a;&#xff08;红色…

GaussDB工作级开发者认证—第五章GaussDB数据库操作与管理

一、数据库对象基本操作 查询数据库&#xff1a; postgres# \l --使用元命令查看数据库 postgres# select * from pg_database; --通过系统表查看数据库 表注意事项: 只有表的所有者有权限执行ALTER TABLE命令&#xff0c;系统管理员默认拥有此权限 不能修改分区表的tables…