让进程能够“相互沟通”的高级方式一:匿名管道

news2024/11/27 19:42:37

代码运行及测试环境:linux centos7.6
在阅读这篇文章时,需要掌握OS对文件管理的基础知识(文件打开表、文件描述符、索引结点…)

前言

我们都知道进程是具有独立性的,意味着进程之间无法相互通信。但在一些情况下,不得不让进程之间进行通信。通信的作用主要有:

  • 数据的传输。
  • 数据的共享。
  • 控制其他进程。

数据的传输、共享是非常容易理解的。为什么需要一个进程去控制另一个进程呢?做一个虚拟的假设,进程A负责检测地铁进站,进程B负责打开地铁门。进程B一直处于休眠状态,当进程A检测出地铁到站停靠后,进程A可以唤醒进程B,打开地铁门。可见,让一个进程去控制另外一个进程,在日常生活中是非常频繁的, 也是十分重要的。

如果要让两个相互独立的进程进行通信,那它们之间需要一个媒介。OS提供了这个媒介,并且对它们之间的通信进行管理。根据OS提供媒介的不同,产生了许多进程间通信的方式,例如:共享内存、消息队列、管道等等。我在这篇文章里只谈论管道通信——匿名管道。

匿名管道的底层原理

首先强调匿名管道只能用于 具有“血缘关系”的进程之间的通信。

当用户请求建立匿名管道时,操作系统会为进程创建一个管道文件,这个文件它并不需要文件名,因为OS建立管道文件后,就会直接把它的文件属性拷贝到打开文件表的一个条目内,用户可以获取到对应的文件描述符,进而读写管道。
在这里插入图片描述
它会让俩个相邻的打开文件表表项同时指向这个管道文件的inode, 是为了读写操作分离,一个文件描述符对应的是写入操作,另一个文件描述符对应的是读取操作。

虽然匿名管道的本质是一个文件,但和普通文件有许多差别。从另外一个角度来看,匿名管道更偏向于解释成一块缓冲区。用户并不是直接将数据写入磁盘上的数据块,也不会直接从磁盘上读取数据出来, 而是以内核缓冲区为媒介。
在这里插入图片描述
由OS再去调用数据从内核缓冲区写入磁盘和读到内核缓冲区的接口。

那么匿名管道是如何实现 具有血缘关系的进程 之间的通信呢?以父子进程间的管道通信为例。
在这里插入图片描述
首先父进程创建一个管道, 再创建子进程,子进程的PCB是以父进程为模板的,父子进程此刻的打开文件表是一样的, 所以父进程文件打开表有两个表项指向管道,子进程打开文件表也有两个表项指向该管道,并且文件描述符此刻是一样的。这样,相互独立的两个父子进程看到了同一份资源——“管道”, 管道自然而然充当了它们通信的媒介。

管道通信是单向通信的,只允许一端进行写入,另一端进行读取。如果要实现管道通信,需要根据情况,关闭对应的读写端。

匿名管道创建过程

我们将上述的过程简化一下
🍍第一步:父进程创建匿名管道
在这里插入图片描述
🥑第二步:父进程创建出子进程
在这里插入图片描述
🍉第三步:根据需要,关闭对应的读端和写端
(这里以父进程写入,子进程读取为例)
在这里插入图片描述

匿名管道的几种情况

创建匿名管道的系统调用pipe

#include <unistd.h>
int pipe(int pipefd[2]);
//pipefd是一个输出型参数:
//pipefd[0]对应读端的文件描述符 pipefd[1]对应写端
//如果创建管道成功返回0,否则返回-1

简单写一个父进程读取管道、子进程写数据进管道的例子。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{
    //1.创建管道
    int pipefd[2];
    if(pipe(pipefd) != 0)
    {
        perror("pipe");
        exit(-1);
    }
    //2.父进程创建出子进程
    if(fork() == 0)
    {
        //child
        //3.1 让子进程写入数据进入管道 ,关闭读端
        close(pipefd[0]);
        const char *str = "i am ydy.";
        while(1)
        {
            write(pipefd[1], str, strlen(str));
            sleep(1);
        }

    }
    else
    {
        //father
        //3.2 父进程从匿名管道种读取数据, 关闭写端
        close(pipefd[1]);
        while(1)
        {
            char buffer[64] = {0};
            ssize_t s = read(pipefd[0], buffer, sizeof(buffer));
            if(s < 0){
                //读取失败
                break;
            }
            else if(s == 0){
                //写端关闭,且数据读取完毕
                printf("child quit...\n");
                break;
            }
            else{
                printf("child say# %s\n", buffer);
            }
        }
    }
    waitpid(-1, NULL, WNOHANG);
    return 0;
}

匿名管道的几种情况:
🌻读端读得慢,写端写得快
🌼读端读得快,写端写得慢
💐写端在写入数据,读端突然关闭
🌷读端在读取数据,写端突然关闭

这几种情况的特点,可以自行检测得出,我在这里直接写结论,当然这些结论的正确性我在此之前都用代码检验过了,毕竟“实践是检验真理的唯一标准”。

🌻读端读得慢,写端写得快

管道内有数据,读端就可以读取。由于写端写得比较快,所以按照趋势下去,管道一定会满。管道满了以后,写端进程会被阻塞,等待读端读取数据。你可能认为,管道满了后,读端读取一份数据,写端就会写入数据,事实并不是这样。实际上,写进程一旦被阻塞,只有管道能够提供一定的空闲空间大小(这个大小具体我并不知道是多少, 在我的机子上跑,测出来的是至少是1kb)后,写进程才会被唤醒。

🌼读端读得快,写端写得慢

由于写的速度赶不上读取的速度, 所以管道极可能某个时刻没有数据。读进程会被阻塞,等待写进程写入数据,直到管道有数据。

💐写端在写入数据,读端突然关闭

管道的作用就是为了让两个进程通信,读端关闭了,写进程又不需要拿取数据,所以读进程不在,管道就没有意义了。所以读端关闭,写进程也会退出。

🌷读端在读取数据,写端突然关闭

写端关闭了,管道内可能还会有数据。读进程是需要拿数据的,管道里的东西还有用,所以读端把数据全部读完后,读进程再退出。

读进程读取得慢,写进程写入得快,会出现这种现象的原因本质上是因为管道是有大小的,在Linux往管道写入64KB数据的时候,写进程就不再写入了,而超过4KB的时候,OS就不再保证管道的写入具有原子性了。对于一端关闭的现象,间接阐述了管道机制必须要有确定对方存在的协调能力。

匿名管道特点

  • 仅限具有血缘关系的进程使用
    根据匿名管道的创建过程可知,匿名管道的本质是一个文件,没有文件名,由用户请求,OS帮助建立后,直接把文件属性拷贝到进程的打开文件表内。血缘关系的进程PCB都是以“父进程”模板创建的,所以子进程以及有血缘关系的进程,打开文件表内都有关于匿名管道的属性。由于没有文件名,其他进程无法自行打开文件,因此非血缘关系的进程间无法使用匿名管道。
  • 匿名管道的生命周期是随进程的
    因为下一次,进程无法打开上一个管道文件(没有文件名)。
  • 管道是单向通信的。
  • 管道是面向字节流的
  • 管道机制必须能够拥有互斥、同步和确定对方存在的协调能力

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

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

相关文章

当我们谈笔记的时候,我们在谈什么

文章具体内容如图&#xff0c;感谢妙友分享好文&#x1f389; 本篇内容来源于网站Untag Minja 上传的内容《当我们谈笔记的时候&#xff0c;我们在谈什么》 如有侵权请联系删除&#xff01;

如何搭建与使用FTP服务器

一、概述 目前用作搭建FTP服务器端的软件有很多&#xff0c;比如 Vsftpd、ProFTPD、PureFTPd、Wuftpd、ServerU、Filezilla Server等&#xff0c;这里使用Vsftpd进行搭建。 vsftpd 是“very secure ftp daemon”的首字母缩写&#xff0c;它是一款在Linux发行版中最受推崇的免…

应用到vscode

随着ChatGPT的热度持续上升&#xff0c;我们也不得不深刻认识到&#xff0c;这已经势不可挡了。我们必须去接受它&#xff0c;甚至是拥抱它。 私信我可以获取最新包 今天呢&#xff0c;我们要介绍的是vscode的一款插件&#xff0c;叫做ChatGPT&#xff1a; 使用方式 安装完成…

Xshell安装使用教程

简介 Xshell 是一个强大的安全终端模拟软件&#xff0c;它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。 Xshell可以在Windows界面下用来访问远端不…

【C#图解教程】第三章 C#编程概述 笔记总结

程序实例 命名空间一组类型声明 using system&#xff1b;表示使用类型库中的system中的所有类 namespace Myspace{}则会创建一个新的命名空间&#xff0c;这个空间中可以声明该空间的类 SimpleProgram中使用了两个命名空间。先是使用了System命名空间中定义的console类&…

【Linux】项目自动化构建工具-make和Makefile 的使用和进度条的实现

文章目录 一、什么是make/makefile二、如何编写makefile三、make 的工作原理1.make的使用2.make的依赖性3.项目清理4..PHONY伪目标 四、Linux第一个小程序 -- 进度条1.\r&&\n2.行缓冲区概念3.进度条process.hprocesstest.cmakefile 一、什么是make/makefile 什么是mak…

【c语言习题】使用链表解决约瑟夫问题

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…

在 Shell 脚本中使用 `exec` 命令的方法和用途

在 Shell 脚本中&#xff0c;exec 是一个非常有用的命令&#xff0c;用于执行命令或替换当前进程。它允许您在脚本中启动新的进程&#xff0c;并将控制权完全转移到新进程。本文将详细介绍在 Shell 脚本中使用 exec 命令的方法和用途。 什么是 Exec 命令&#xff1f; exec 是一…

python基础----02-----字面量、变量、数据类型及其转换、标识符以及字符串、数据输入(input语句)

一 字面量 1 字面量 字面量&#xff1a;在代码中&#xff0c;被写下来的的固定的值称之为字面量。类似C/C的字符串常量。 1.1 常见的python值类型 Python中常见的值类型&#xff1a; 实际上在C/C字面量和这里的类型还是有区别的&#xff0c;体现在内存存储中&#xff0c;字…

JavaScript正则表达式

1.介绍 2.语法 3.元字符 4.修饰符 目标&#xff1a;学习正则表达式概念及语法&#xff0c;编写简单的正则表达式实现字符的查找或检测。 一、介绍 1.什么是正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是用于匹配字符串中字符组合的模式。&#xff08;…

设计模式之~原型模式

定义&#xff1a;用原型实例指导创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象&#xff0c;而且不需知道任何创建的细节。 优点&#xff1a; 一般在初始化的信息不发生变化的情况下&#xff0c;克隆是最…

触摸屏驱动的问题,在C站搜文章一下午解决不了,最后ChatGpt解决了

目录 一、遇到问题二、在C站搜索文章去解决问题的收获三、用 ChatGpt 去解决的收获四、总结 一、遇到问题 现实问题&#xff1a; 有一个基于Linux4.19内核开发了&#xff0c;在海思SS528芯片运行的系统&#xff0c;用鼠标可以正常使用。 现在要求使用一块公司开发的 多点触控屏…

ES+Redis+MySQL,这个高可用架构设计

一、背景 会员系统是一种基础系统&#xff0c;跟公司所有业务线的下单主流程密切相关。如果会员系统出故障&#xff0c;会导致用户无法下单&#xff0c;影响范围是全公司所有业务线。所以&#xff0c;会员系统必须保证高性能、高可用&#xff0c;提供稳定、高效的基础服务。 …

window10安装vim编辑器

我们在做git操作的时候&#xff0c;很多文字编辑工作会默认打开 Vim 编辑器来进行操作。 Vim 是一个高度可配置的文本编辑器&#xff0c;旨在让创建和更改任何类型的文本变得非常高效。大多数 UNIX 系统和 Apple OS X 都将它作为vi包含在内&#xff0c;用惯了Linux中的Vim编辑器…

机器学习实战7-基于机器学习算法预测相亲成功率

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战7-基于机器学习算法预测相亲成功率&#xff0c;随着社会的发展&#xff0c;大家都忙于事业&#xff0c;对自己的终身大事就耽搁了&#xff0c;相亲是一种传统的寻找伴侣的方式&#xff0c;随着时代的发…

谷歌训了28个15亿参数模型,说明数据对大模型训练的影响

夕小瑶科技说 原创 作者 | Python 随着ChatGPT的爆火&#xff0c;大规模语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;如日中天。然而&#xff0c;由于相关数据细节并不公开&#xff0c;相关研究大多都是盲人摸象式探索&#xff0c;缺乏系统的经验指导…

关于打卡小程序可能会遇到的部分问题【华为云Astro低代码体验季】

关于打卡小程序可能会遇到的部分问题【华为云Astro低代码体验季】 前提一、可能遇到的问题二、 改进 前提 已经注册华为云账号且浏览过 &#xff1a;华为云Astro制作打卡小程序&#xff0c;在此基础上可能会遇到的问题 一、可能遇到的问题 当创建完成应用后&#xff0c;如果…

设计模式之~外观模式

定义&#xff1a; 为子系统中的一组接口提供一个一致的界面&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 结构图&#xff1a; 区分中介模式&#xff1a; 门面模式对外提供一个接口 中介模式对内提供一个接口 优点&#xff1a; 松耦…

【算法题解】32. 验证二叉搜索树的递归解法

这是一道 中等难度 的题 https://leetcode.cn/problems/validate-binary-search-tree/ 题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含…

【瑞萨RA_FSP】DMAC/DTC编程实战

文章目录 一、DMAC存储器到存储器传输二、DTC外部中断触发传输 一、DMAC存储器到存储器传输 1. FSP配置 打开该工程的 FSP 配置界面。然后按如图步骤加入 DMAC。 加入 DMAC 后如下图所示。 单击上图中新添加的 r_dmac 框&#xff0c;然后在左下角的“属性”窗口配置 DMAC 模…