【Linux进程间通信】匿名管道

news2024/7/10 19:53:44

【Linux进程间通信】匿名管道

目录

  • 【Linux进程间通信】匿名管道
      • 进程间通信介绍
        • 进程间通信目的
        • 进程间通信发展
        • 进程间通信分类
    • 管道
        • 用fork来共享管道原理
        • 站在文件描述符角度——深度理解管道
        • 站在内核角度——管道本质
      • 匿名管道
        • 在myshell中添加管道的实现:
        • 管道读写规则
        • 管道特点

作者:爱写代码的刚子

时间:2023.11.21

前言:本篇博客将会介绍匿名管道的运用

进程间通信介绍

前言:因为进程独立性的存在,导致进程通信的成本比较高。为什么要进行进程间通信?基本数据,发送命令,某种协同,通知。

进程间通信目的
  • 数据传输:一个进程需要将它的数据发送给另一个进程

  • 资源共享:多个进程之间共享同样的资源。

  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

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

a. 进程间通信的本质:必须让不同的进程看到同一份“资源”

b. “资源”?特定形式的内存空间

c. 这个“资源”由操作系统提供,为什么不是我们两个进程中的一个呢?假设一个由一个进程提供,这个资源被这个进程独有,破坏进程独立性。

d. 我们进程访问这个空间,进行通信,本质就是访问操作系统!进程代表的就是用户,“资源”从创建,使用(一般),释放,都是调用系统调用接口!从底层设计,从接口设计,都要由操作系统独立设计。一般操作系统会有一个独立的通信模块——隶属于文件系统——IPC通信模块定制标准(进程间通信是有标准的)——System V &&posix

进程间通信发展
  • 管道

  • System V进程间通信

  • POSIX进程间通信

进程间通信分类

管道

  • 匿名管道pipe
  • 命名管道

System V IPC

  • System V 消息队列

  • System V 共享内存

  • System V 信号量

POSIX IPC

  • 消息队列

  • 共享内存

  • 信号量

  • 互斥量

  • 条件变量

  • 读写锁

管道

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

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

在这里插入图片描述

  • who | wc -l统计在云端服务器中的用户个数。

管道打开的是内存级文件(管道就是文件),每个文件有着对应的缓冲区,不同进程打开同一个文件时存在引用计数来进行控制。

管道并不支持同时读写!

回顾文件系统
在这里插入图片描述

无论对文件怎么读写,首先都需要将文件加载到内存中。既然如此,我们也可以创建一个内存级文件(技术上可行)。

注意!!!!!,如果该进程创建了子进程,子进程中的struct file*fd_arry数组中存放相同的指针,但是指向的文件相同!!!!

在这里插入图片描述

  • 所以存在引用计数解决父进程关闭子进程仍然在读取文件的情况。
用fork来共享管道原理

在这里插入图片描述

站在文件描述符角度——深度理解管道

在这里插入图片描述

  • 注意,如果两个进程间没有关系(看不到同一份资源),就不能用上述方法进行通信,如果要通信,则需要采用下面匿名管道的方法。

  • 所以要想进行上述通信,进程间必须是父子关系,兄弟关系,爷孙关系…(血缘关系,常用于父子关系)

站在内核角度——管道本质

在这里插入图片描述

  • 【问题】:管道只能单向通信,如果我们需要进行双向通信呢?(建立多个管道)

  • 至此进程间通信了吗?没有,只是建立了通信信道——为什么怎么费劲??——进程具有独立性,通信是有成本的!!!

匿名管道

#include <unistd.h>

功能:创建一无名管道

原型

int pipe(int fd[2]);int fd[2]为输出型参数,将文件的文件描述符数字带出来,让用户使用!!(pipefd[0]:读下标,pipefd[1]:写下标

参数

fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端

返回值:成功返回0,失败返回错误代码

在这里插入图片描述

  • 简单的代码示例:

示例一:查看pipefd数组的值

在这里插入图片描述

一般来说==pipefd[0]为读,pipefd[1]为写==。

示例二:子进程打印数据父进程读取数据:

示例代码:

#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <sys/wait.h>
#include <string.h>
#define N 2
#define NUM 1024

using namespace std;

void Writer(int wfd)
{
    string s = "hello";
    pid_t self = getpid();
    int number = 0;

    char buffer[NUM];
    while(true)
    {
        buffer[0]=0;//字符串清空,将这个数组当作字符串
        snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,number++);

        write(wfd,buffer,strlen(buffer));//strlen(buffer)不需要加1,c语言规定的‘\0’不关文件的事,只需要文件内容即可
        sleep(1);
    }
}

void Reader(int rfd)
{
    char buffer[NUM];
    while(true)
    {
        buffer[0] = 0;
        ssize_t n = read(rfd,buffer,sizeof(buffer));//注意 sizeof != strlen,管道满了怎么办?管道有面向字节流概念,之后学习网络会提到(定协议去区分)。
        if(n > 0)
        {
            buffer[n] = 0;// 0 == '\0'当作字符串
            cout<< "父进程得到了一个消息:"<< getpid() << "]#" << buffer <<endl;
        }
    }
}

int main()
{
    int pipefd[N] = {0};
    int n = pipe(pipefd);
    if(n<0)return 1;

    cout << "pipefd[0]:" << pipefd[0] << ", pipefd[1]:  "<<pipefd[1] << endl;

    pid_t id = fork();
    if(id < 0) return 2;
    if(id == 0)
    {
        //子进程
        close(pipefd[0]);//关闭读

        //IPC code
        Writer(pipefd[1]);

        close(pipefd[1]);
        exit(0);
    }
    //父进程
    close(pipefd[1]);//关闭写

    //IPC code
    Reader(pipefd[0]);

    pid_t rid = waitpid(id,nullptr,0);
    if(rid < 0) return 3;
    close(pipefd[0]);  
    return 0;
}

结果:

在这里插入图片描述

  • 父子进程在对同一份数据进行访问时,这份资源是多执行流共享的,难免会出现访问冲突的问题。(临界资源竞争的问题)但是父子进程会进行协同。对于管道文件会发生同步与互斥————保护管道文件的数据安全。

  • 同时子进程向管道中写入的都是字符,父进程进行读取时也是字符,所以不会出换行的情况。(忽视分隔符等特殊符号,就相当于字节)(管道是面向字节流的)

总结:

管道的特征:

  1. 具有血缘关系的进程进行进程间通信
  2. 管道只能单向通信
  3. 父子进程是会进程协同的,同步与互斥——保护管道文件的数据安全(多线程)
  4. 管道是有固定大小的(会被写满,但是在不同的内核里大小不同)
  5. 管道是面向字节流的(网络)
  6. 管道是基于文件的,而文件的生命周期是随进程的
  • ulimit -a查看相关的限制(open files表示单个进程最多打开文件的个数 )

在这里插入图片描述

  • man 7 pipe查看管道大小

在这里插入图片描述

  • 官方文档中说了,如果读取的数据小于PIPE_BUF,读取操作就必须是原子的
在myshell中添加管道的实现:

思路:

  • 分析输入的命令行字符串,获取有多少个|, 命令打散多个子命令字符串

  • malloc申请空间,pipe先申请多个管道

  • 循环创建多个子进程,每一个子进程的重定向情况。最开始. 输出重定向, 1->指定的一个管道的写端

  • 中间:输入输出重定向, 0标准输入重定向到上一个管道的读端 1标准输出重定向到下一个管道的写端

  • 最后一个:输入重定向,将标准输入重定向到最后一个管道的读端

  • 分别让不同的子进程执行不同的命令— exec* — exec*不会影响该进程曾经打开的文件,不会影响预先设置好的管道重定向

管道读写规则

管道的4中情况:

  1. 读写端正常,管道如果为空,读端就要阻塞
  2. 读写端正常,管道如果被写满,写端就要阻塞
  3. 读端正常读,写端关闭,读端就会读到0,表明读到了文件(pipe)结尾,不会被阻塞
  4. 写端是正常写入,读端关闭了。操作系统就要杀掉正在写入的进程。(通过信号干掉)
  • 当没有数据可读时

    • O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
    • O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
  • 当管道满的时候

    • O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
    • O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
  • 如果所有管道写端对应的文件描述符被关闭,则read返回0

  • 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出

  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

管道特点

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创

建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

管道提供流式服务

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

一般而言,内核会对管道操作进行同步与互斥

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


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

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

相关文章

Linux 多线程 | 线程的概念

线程的概念 线程是一个执行分支&#xff0c;执行粒度比进程更细&#xff0c;调度成本更低&#xff1b; 线程是进程内部的一个执行流&#xff1b; 线程是CPU调度的基本单位&#xff0c;进程是承担分配系统资源的基本实体。 之前我们学习过虚拟地址空间的知识&#xff0c;知道…

大礼包 - 华为机试真题题解

考试平台&#xff1a; 时习知 分值&#xff1a; 200分&#xff08;第二题&#xff09; 考试时间&#xff1a; 2024-01-31 &#xff08;两小时&#xff09; 题目描述 某公司针对新用户推出大礼包&#xff0c;从任意一天注册开始&#xff0c;连续登陆 x 天&#xff0c;每天可以领…

C# 信号量(Semaphore)详细使用案例

文章目录 简介信号量的工作原理使用场景使用示例其他使用实例1. 数据库连接池管理2. 文件读写同步3. 生产者消费者问题4. 打印任务队列同步5. Web服务器并发请求限制 简介 在C#中&#xff0c;信号量&#xff08;Semaphore&#xff09;是.NET框架提供的一个同步类&#xff0c;位…

vue3:23—自定义hooks

正是因为有了hooks&#xff0c;组合式才发挥出了威力 其实 hooks 和 vue2 中的 mixin 有点类似&#xff0c;但是相对 mixins 而言&#xff0c; hooks 更清楚复用功能代码的来源, 更清晰易懂。 如何定义hooks 具备可复用功能&#xff0c;才需要抽离为 hooks 独立文件函数名/文…

【Linux】Ext2 文件系统

文件系统 前言一、磁盘硬件1. 磁盘的物理存储结构2. 磁盘存储的逻辑抽象结构 二、理解 Ext2 文件系统1. 初步理解文件系统2. 深入理解文件系统&#xff08;1&#xff09;inode Table&#xff08;2&#xff09;Data blocks&#xff08;3&#xff09;inode Bitmap&#xff08;4&a…

Lambda表达式(匿名函数)

C11中引入了lambda表达式&#xff0c;定义匿名的内联函数。 我们可以直接原地定义函数而不用再跑到外面去定义函数跳来跳去。 同时在stl的排序上也有作用。 [capture] (parameters) mutable ->return-type {statement}下面逐一介绍各个参数的含义. [capture] : 捕获&#…

【Spring】自定义注解 + AOP 记录用户的使用日志

目录 ​编辑 自定义注解 AOP 记录用户的使用日志 使用背景 落地实践 一&#xff1a;自定义注解 二&#xff1a;切面配置 三&#xff1a;Api层使用 使用效果 自定义注解 AOP 记录用户的使用日志 使用背景 &#xff08;1&#xff09;在学校项目中&#xff0c;安防平台…

阿里计算巢:开启数据集市场的宝库,助力AI研究和应用

阿里计算巢 阿里数据巢提供了一个丰富的数据集市场&#xff0c;官方地址&#xff1a; https://computenest.console.aliyun.com/dataset/service/cn-hangzhou 可以看到数据集内容涵盖了多个领域&#xff0c;且还在不断增加中。关键是免费&#xff01;且支持下载到本地。 以下…

oracle 根据身份证号码与指定日期计算年龄

自定义函数&#xff1a; CREATE OR REPLACE FUNCTION 获取年龄(身份证号 varchar2, 指定时间 date) RETURN varchar2 AS 年龄 varchar2(16); BEGINif length(身份证号) >18 thenSELECT TRUNC( MONTHS_BETWEEN(指定时间, TO_DATE(SUBSTR(身份证号, 7, 8), YYYYMMDD) …

Django学习记录01

1.项目结构 djangoProject02 ├── manage.py 【项目的管理&#xff0c;启动项目、创建app、数据管理】【不要动】【常常用】 └── jangoProject02 ├── __init__.py ├── settings.py 【项目配置】 【常常修改】 ├── urls.py …

Linux 查看系统信息 + 服务信息命令(简记)

概述 作用&#xff1a;Linux 运维工作中常用的命令速查 小步教程 (xiaobuteach.com) Linux 命令大全 | 菜鸟教程 (runoob.com) 文本编辑器vim 本章大纲 | 小步教程 vim 多文件编辑 | 小步教程 常用 ps 查看服务启动命令 Linux ps 命令 | 菜鸟教程 (runoob.com) # 查找…

Linux进程信号处理:深入理解与应用(2​​)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;its 6pm but I miss u already.—bbbluelee 0:01━━━━━━️&#x1f49f;──────── 3:18 &#x1f504; ◀️…

32ADC模数转换器&AD单通道&多通道

目录 一.简介 二.逐次逼近法​编辑 三.结构框图 四.小tips (1)转换模式 &#xff08;2&#xff09;触发控制 &#xff08;3&#xff09;数据对齐 &#xff08;4&#xff09;转换时间 &#xff08;5&#xff09;校准 &#xff08;6&#xff09;硬件电路 五.相关函数 …

Java语法学习IO流

Java语法学习IO流 大纲 文件IO流 具体案例 1. 文件 基本介绍 创建文件 第一种&#xff1a; public static void main(String[] args) {String filePathName "d:\\news1.txt";File file new File(filePathName);try {file.createNewFile();} catch (IOExceptio…

vulhub中Apache Druid 代码执行漏洞复现(CVE-2021-25646)

Apache Druid是一个开源的分布式数据存储。 Apache Druid包括执行嵌入在各种类型请求中的用户提供的JavaScript代码的能力。这个功能是为了在可信环境下使用&#xff0c;并且默认是禁用的。然而&#xff0c;在Druid 0.20.0及以前的版本中&#xff0c;攻击者可以通过发送一个恶…

2018 年全国职业院校技能大赛高职组“信息安全管理与评估”赛项任务书(笔记解析)

1. 网络拓扑图 2. IP 地址规划表 3. 设备初始化信息 阶段一 任务 1:网络平台搭建 1、根据网络拓扑图所示,按照 IP 地址参数表,对 WAF 的名称、各接口 IP 地址 进行配置。 2、根据网络拓扑图所示,按照 IP 地址参数表,对 DCRS 的名称、各接口 IP 地址 进行配置。 3、根据网…

C++项目 -- 高并发内存池(二)Thread Cache

C项目 – 高并发内存池&#xff08;二&#xff09;Thread Cache 文章目录 C项目 -- 高并发内存池&#xff08;二&#xff09;Thread Cache一、高并发内存池整体框架设计二、thread cache设计1.整体设计2.thread cache哈希桶映射规则3.TLS无锁访问4.thread cache代码 一、高并发…

CCF迎来新风采:揭晓2024-2026年度执行机构负责人名单!

会议之眼 快讯 中国计算机学会&#xff08;CCF&#xff09;成立于1962年&#xff0c;是一家全国性学会&#xff0c;拥有独立社团法人地位&#xff0c;同时是中国科学技术协会的会员单位。作为中国计算机及相关领域的学术团体&#xff0c;CCF的宗旨在于为该领域专业人士的学术和…

C

extern int a; //同一个项目声明 int r a > b ? a : b; 错误 scanf 不输入‘\n’,getchar()输入\n; printf()返回值 0次 system("cls"); 可以调用命令行函数 time(NULL)时间戳 srand((unsigned)time(NULL)); //随机数种子 int rev rand()%1001; //随…

Linux---yum命令详解

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.概念2.yum的配置信…