010 Linux 进程间通信_匿名管道

前言

本文将会向你介绍匿名管道的原理以及用法,以及管道的使用存在的情况和管道的特性

文章重点

重点:匿名管道的原理,使用情况,以及特性

进程间通信

进程间通信的本质:

让不同的进程先看到同一份资源,这个资源不能由A,B进程提供,但能够被进程申请,资源通常都是由OS提供

进程间通信目的:

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

进程间通信分类

一、管道
匿名管道pipe
命名管道
二、System V IPC
System V 消息队列
System V 共享内存
System V 信号量
三、POSIX IPC
消息队列
共享内存
信号量
互斥量
条件变量
读写锁

今天要介绍的就是进程间通信的其中一种形式管道——匿名管道

什么是管道

在刚学linux的时候,在linux常见指令的那一讲,我们介绍过 | 管道符。 Linux管道符“|”用于将一个命令的输出传递给另一个命令作为输入。基本用法如下: command1 | command2

什么是匿名管道

匿名管道是通过调用系统函数pipe()创建的,不需要指定一个路径来标识管道。它只是一个临时的通道,存在于内存中,只能用于具有亲缘关系的进程之间通信(后续使用fork函数来实现)。

匿名管道的实现原理

首先要让不同的进程看到同一份资源,通过fork函数创建子进程,这样一来,子进程就会拷贝父进程的文件描述符表,再通过pipe创建匿名管道,父子进程通过相同的文件描述符指向同一个文件,意味着它们指向同一个页缓冲区,再用系统调用接口write写入数据到管道,read从管道中读取数据,即可完成父子进程之间的通信

在这里插入图片描述
pipe函数的用法

头文件:#include <unistd.h>
功能:创建一无名管道
原型 int pipe(int fd[2]);
参数 fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码
pipe函数的参数是一个输出型参数,返回两个文件描述符。管道被创建时,会需要使用两个文件描述符,一个文件描述符用于向管道写数据,一个文件描述符用于从管道读数据

在这里插入图片描述

首先通过pipe函数打开一个文件的读写端
在这里插入图片描述
通过fork函数,子进程能够继承读写端
在这里插入图片描述
再进行适当的关闭读写端(保留一个读一个写),这样未来能形成单向通道
在这里插入图片描述

创建管道并通信

这里设计的是让子进程写入,让父进程读取(这样做的好处是当子进程退出时,可以通过wait等待获取子进程的退出错误码)

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX 100using namespace std;
int main()
{//创建管道int pipefd[2] = {0};int n = pipe(pipefd);//判断是否成功(一般都会成功,有确定预测的用assert,不确定的用if)assert(n==0);//防止在release模式下,assert失效,后续不会使用n会告警//void(n);cout << "pipefd[0]:" << pipefd[0] << ",pipefd[1]:" << pipefd[1] << endl;//创建子进程pid_t id = fork();//判断是否创建失败if(id < 0){perror("fork");return 1;}//子进程else if(id == 0){close(pipefd[0]);     //关闭读通道int cnt = 10;while(cnt){char message[MAX];snprintf(message, sizeof(message), "hello father, I am child, Mypid:%d, cnt: %d", getpid(), cnt);cnt--;//将字符串message写入到管道中write(pipefd[1], message, strlen(message));sleep(1);   //让子进程写慢些// char c = 'F';// write(pipefd[1], &c, 1);// cnt++;// cout << cnt << ":" << "writing..." << endl;}exit(0);}//父进程close(pipefd[1]);   //关闭写通道//TODOchar buffer[MAX];while(true){sleep(1);//从文件描述符对应的管道里读取数据,并将数据存储到buffer中size_t n = read(pipefd[0], buffer, sizeof(buffer) - 1);if(n > 0){buffer[n] = 0;cout << getpid() << " -> "<< " " << "child sends: " << buffer << " to me!" << endl; }else if(n == 0){   cout << "father return val(n):" << n << endl;cout << "child quit, me too!!!" << endl;sleep(1);break;}}   cout << "finish reading..." << endl;//写端已经退出,读完后关闭读端close(pipefd[0]);pid_t rid = waitpid(id, nullptr, 0);if(rid == id){cout << "wait success" << endl;}return 0;
}

管道的四种情况

1、如果管道没有数据了,读端必须等待,直到有数据为止

写入一条数据后,就让子进程进入休眠状态
在这里插入图片描述
现象:读端不再打印(读取数据),等待子进程写入
在这里插入图片描述

2、正常情况:如果管道被写满了,那么写端必须等待,直到有空间为止(读端读走数据)

让读端先睡一会,让写端一次写一个字节
在这里插入图片描述
现象:这里会将管道写满64KB,然后就不再写入了
在这里插入图片描述

3、写端关闭,读端一直读,读端会读到read返回值为0,表示读到文件结尾

让子进程写5条就退出
在这里插入图片描述
现象:read返回值为0,表示读完了
在这里插入图片描述

4、读端关闭(读一次直接break,然后关掉读端的文件描述符),写端一直写,写入就没有意义了,写端直接挂掉了,对于操作系统来说,不会做消耗资源的事情(直接杀掉写端进程,通过向目标进程发送sigpipe(13)信号,终止目标进程)

直接在最后break
在这里插入图片描述

现象:写端挂掉了
在这里插入图片描述
在这里插入图片描述

管道的五种特性

1、匿名管道,可以允许具有血缘关系的进程之间进行进程间通信,常用于父子,兄弟,爷孙都可以
毫不相关的进程,是不能通过这种管道进行通信的,是通过fork来通信的
2、匿名管道,默认给读写端要提供同步机制(没有管道的时候,父子进程都向显示器打印,你打你的,我打我的,有了管道,读端就等待写端)
3、匿名管道是面向字节流的,写10次,可以读一次全部读完,也可以一条条读,怎么write和怎么read无关
4、管道的生命周期是随进程的(整个管道会被释放掉,管道也是底层文件,父子进程退出后,管道没有人用了,会被os回收)
5、管道是单向通信的一种特殊情况

小结

今日的分享就到这里啦,如果本文存在疏漏或错误的地方,还请您能够指出!

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

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

相关文章

EasyRecovery2024免费无需付费版电脑数据恢复软件

一、功能概述 EasyRecovery数据恢复软件是一个功能全面的数据恢复工具&#xff0c;其主要功能包括&#xff1a; 文件恢复&#xff1a;能够恢复各种文件类型&#xff0c;如文档、图片、视频、音频等&#xff0c;满足用户多样化的数据恢复需求。分区恢复&#xff1a;当硬盘分区…

vue2 设置keepAlive之后怎么刷新页面数据

场景&#xff1a;移动端有 A、B、C 三个页面&#xff0c;A、B 页面路由设置了keepAlive属性&#xff0c;有下面两个场景&#xff1a; 1、A 页面 --> B 页面&#xff0c;B 页面刷新。 2、C 页面 --> B页面&#xff0c;B 页面不刷新。 一、分为以下两个情况讨论&#xf…

智能咖啡厅助手:人形机器人 +融合大模型,行为驱动的智能咖啡厅机器人(机器人大模型与具身智能挑战赛)

智能咖啡厅助手&#xff1a;人形机器人 融合大模型&#xff0c;行为驱动的智能咖啡厅机器人(机器人大模型与具身智能挑战赛) “机器人大模型与具身智能挑战赛”的参赛作品。的目标是结合前沿的大模型技术和具身智能技术&#xff0c;开发能在模拟的咖啡厅场景中承担服务员角色并…

136. 只出现一次的数字【简单】

136. 只出现一次的数字【简单】 题目描述&#xff1a; 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使…

TonePlayer音调播放器开发

音调播放器 根据蜂鸣器的声音频率、播放长短和声音大小&#xff0c;来产生设备需要的音频&#xff1a;比如设备启动声音、设备关机音、故障音、连接成功音、断开连接音、信号不稳定提示音、充电启动提示音、充电关闭提示音、设备插入提示音、设备拔出提示音、无操作提示音以及需…

Windows系统搭建VisualSVN并结合内网穿透实现远程访问本地服务

文章目录 前言1. VisualSVN安装与配置2. VisualSVN Server管理界面配置3. 安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4. 固定公网地址访问 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源代码的版本控制系统…

Vue.js+SpringBoot开发音乐偏好度推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1.2 我的喜好模块2.1.3 每日推荐模块2.1.4 通知公告模块 2.2 用例图设计2.3 实体类设计2.4 数据库设计 三、系统展示3.1 登录注册3.2 音乐档案模块3.3 音乐每日推荐模块3.4 通知公告模…

C++ //练习 10.15 编写一个lambda,捕获它所在函数的int,并接受一个int参数。lambda应该返回捕获的int和int参数的和。

C Primer&#xff08;第5版&#xff09; 练习 10.15 练习 10.15 编写一个lambda&#xff0c;捕获它所在函数的int&#xff0c;并接受一个int参数。lambda应该返回捕获的int和int参数的和。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;v…

PID闭环控制算法的学习与简单使用

平台&#xff1a;matlab2021b&#xff0c;Vivado2018 应用场景和理解 一个早餐店&#xff0c;假如一天都有生意&#xff0c;生意有的时间很火爆&#xff0c;有时候又一般&#xff0c;老板又是个实在人&#xff0c;只知道在后厨蒸包子。由于包子蒸熟需要一定的时间&#xff0c;老…

vscode更新至1.86版本后,ssh远程连接服务器出现异常

问题 you are connected to an OS version that is unsupported by Visual Studio Code 你已连接到不受Visual Studio Code支持的OS 版本 原因是vscode更新到1.86版本后要求远程连接服务器的内核版本和库版本需要符合下面条件。 解决方法 因此有两种方法解决 1.更新服务器…

Transformer之Residuals Decoder

The Residuals 我们需要提到的编码器架构中的一个细节是&#xff0c;每个编码器中的每个子层(self-attention,&#xff0c;ffnn)周围都有一个残余连接&#xff0c;然后是 layer-normalization 步骤。 如果我们要可视化向量和与 self attention 相关的 layer-norm 运算&#x…

记一次dockerfile无法构建问题追溯

我有一个dockerfile如下&#xff1a; ENTRYPOINT ["/sbin/tini"&#xff0c;"-g", "--"] CMD /home/scrapy/start.sh 我原本的用意是先启动tini&#xff0c;再执行下面的cmd命令启动start.sh。 为啥要用tini&#xff1f; 因为我的这个docker…