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 100

using 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]);   //关闭写通道
    //TODO
    char 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、管道是单向通信的一种特殊情况

小结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

换个角度看境外支付系统:警惕金融风险之安全测试实践

【面试突击班】1. 性能测试主要关注哪些指标&#xff1f; &#xff0c;这个名词相信生活在当下社会的大家应该都不在陌生了吧&#xff0c;他时时刻刻充斥在我们的日常生活中&#xff0c;哪里有交易发生&#xff0c;哪里就有它的身影。 其实直白的来说&#xff0c;支付系统是扮…

数组传参调试小技巧

数组传参调试小技巧 前言正文 前言 亲爱的小伙伴们&#xff0c;你们好呀&#xff01;我是莹莹&#xff0c;今天我来给大家分享关于数组传参调试的技巧&#xff0c;希望能够帮助你们&#xff01; 正文 首先&#xff0c;我们先来看一段数组传参代码 #include<stdio.h>v…

《汇编语言》- 读书笔记 - 第16章-直接定址表

《汇编语言》- 读书笔记 - 第16章-直接定址表 16.1 描述了单元长度的标号&#xff08;数据标号&#xff09;检测点 16.1 16.2 在其他段中使用数据标号assume通过标号取地址检测点 16.2 16.3 直接定址表&#xff08;Direct Addressing Table&#xff09;例1分析代码效果 例2分析…

深入了解 Android 中的 FrameLayout 布局

FrameLayout 是 Android 中常用的布局之一&#xff0c;它允许子视图堆叠在一起&#xff0c;可以在不同位置放置子视图。在这篇博客中&#xff0c;我们将详细介绍 FrameLayout 的属性及其作用。 <FrameLayout xmlns:android"http://schemas.android.com/apk/res/androi…

Tomcat常见配置(基础功能、虚拟主机、搭建博客)

目录 一、Tomcat基础功能 1、自动解压war包 2、Tomcat工具界面 2.1 Server Status (服务器状态) 2.1.1 本地登录状态页 2.1.2 远程登录状态页 2.2 Manager App (管理应用程序) 2.3 Host Manager (主机管理器) 3、Context 配置 二、配置虚拟主机 三、搭建 JPress 博客…

就业班 2401--2.29 Linux Day8--存储管理2(LVM)+swap+磁盘阵列raid

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;小伙伴们一定要看到最后&#xff0c;有彩蛋呢^--^ 一、存储管理Ⅱ 逻辑卷LVM &#xff08;Logical Volume Manager&#xff08;逻辑卷管理&#xff09;的简写&#xff09; LVM管理 lvm概念&#xf…

网络编程作业day4

广播模型&#xff1a; 发送端&#xff1a; #include <myhead.h> int main(int argc, const char *argv[]) {//创建套接字int sfdsocket(AF_INET,SOCK_DGRAM,0);if(sfd-1){perror("socket error");return -1;}//设置套接字允许广播属性int broadcast1;if(sets…

MySQL 用户账号迁移

文章目录 前言1. 工具安装1.1 下载安装包1.2 编译安装 2. 用户迁移后记 前言 有一个典型的使用场景&#xff0c;就是 RDS 下云大多数都是通过 DTS 进行数据传输的&#xff0c;用户是不会同步到自建数据库的。需要运维人员在自建数据库重新创建用户&#xff0c;如果用户数量很多…

springboot,druid动态数据源切换

关键字&#xff1a;springboot&#xff0c;druid数据库连接池&#xff0c;两个数据源&#xff08;可以切换成多个&#xff09;&#xff0c;事务管理 关于druid简介传送门&#xff1a;https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 具体分为四…

LeetCode148.排序链表

题目 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 输入&#xff1a;head [] 输出&#xff1a;[] 思路…

STM32CubeIDE基础学习-新建STM32CubeIDE基础工程

STM32CubeIDE基础学习-新建STM32CubeIDE基础工程 前言 有开发过程序的朋友都清楚&#xff0c;后面开发是不需要再新建工程的&#xff0c;一般都是在初学时或者有特殊需要的时候才需要新建项目工程的。 后面开发都是可以在这种已有的工程上添加相关功能就行&#xff0c;只要前…

sylar高性能服务器-日志(P43-P48)内容记录

文章目录 P43&#xff1a;Hook01一、HOOK定义接口函数指针获取接口原始地址 二、测试 P44-P48&#xff1a;Hook02-06一、hook实现基础二、class FdCtx成员变量构造函数initsetTimeoutgetTimeout 三、class FdManager成员变量构造函数get&#xff08;获取/创建文件句柄类&#x…

华工的各类型PPT模板

华工的各类型PPT模板&#xff0c;包括原创的PPT及改良内容的PPT&#xff0c;适合科研/比赛/组会汇报等 前言各种毕业答辩夏令营答辩复试答辩奖学金答辩比赛/项目答辩组会汇报 前言 设计不易&#xff0c;排版不易&#xff0c;内容编排不易 待更新项目1 原创声明&#xff1a;不经…

17 easy 290. 单词规律

//给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 // // 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 // // // // 示例1: // // //输入: patte…

Kubernetes 学习总结(46)—— Pod 不停重启问题分析与解决

我们在做性能测试的时候&#xff0c;往往会发现我们的pod服务&#xff0c;频繁重启&#xff0c;通过kubectl get pods 命令&#xff0c;我们来逐步定位问题。 现象:running的pod&#xff0c;短时间内重启次数太多。 定位问题方法:查看pod日志 kubectl get event …

攻防世界 php_rce

已经给了开发框架了用的是ThinkPHP V5 所以我们直接搜这个框架爆出来的漏洞就好了 可以得到这里面有个远程rce payload url/index.php?s/index/\think\app/invokefunction&functioncall_user_func_array&vars[0]system&vars[1][]dir 然后我们就可以命令执行了…

【大厂AI课学习笔记NO.63】模型的维护

说是模型的维护&#xff0c;其实这堂课都是在讲“在工业环境中开发和部署机器学习模型的流程”。 上图来自于我的笔记思维脑图&#xff0c;已经上传&#xff0c;要链接的访问的主页查看资源。 一路走来&#xff0c;我们学习了数据管理、模型学习、模型验证、模型部署等重要的步…

Elixir 依赖 (deps) 调试的小技巧

最近使用 Elixir 有点多, 经常需要观察一些依赖 (Deps) 的实现, 比如想加个日志打印点 IO.inspect 啥的观察下某个变量&#xff0c;才能更好的理解某个 Elixir 的依赖。这里介绍下一些调试的方式: 这里以 yeshan333/ex_integration_coveralls 为例子. 我们先 clone 项目到本地…

每日五道java面试题之mysql数据库篇(四)

目录&#xff1a; 第一题&#xff1a; Hash索引和B树所有有什么区别或者说优劣呢?第二题&#xff1a;数据库为什么使用B树而不是B树&#xff1f;第三题&#xff1a;B树在满足聚簇索引和覆盖索引的时候不需要回表查询数据&#xff1f;第四题&#xff1a;什么是聚簇索引&#xf…

案例介绍:汽车维修系统的信息抽取技术与数据治理应用(开源)

一、引言 在当今汽车产业的快速发展中&#xff0c;软件已经成为提升车辆性能、安全性和用户体验的关键因素。从车载操作系统到智能驾驶辅助系统&#xff0c;软件技术的进步正在重塑我们对汽车的传统认知。我有幸参与了一个创新项目&#xff0c;该项目专注于开发和集成先进的汽…