学习系统编程No.20【进程间通信之命名管道】

这篇具有很好参考价值的文章主要介绍了学习系统编程No.20【进程间通信之命名管道】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言:

北京时间:2023/4/15/10:34,今天起床时间9:25,睡了快8小时,昨天刷视屏刷了一个小时,本来12点的时候发完博客洗把脸就要睡了,可惜,看到了一个标题,说实话,现在的标题党是懂人性的,接下来就是无法自拔的一个小时快乐时光,但导致莫名间接熬夜,你说烦人不烦人!但是不怕,这个星期5天,几乎没有摆烂,只要今天和明天不摆烂 ,这个星期就是成功滴,一想美滋滋!所以让我们抓紧进入今天的学习吧! 今天我们就正式学习有关内存共享的知识,当然还有管道遗落的知识,因为管道真的是太经典了,但是前提是,现在我要去把我的被单和毯子给晒一晒,不然晚上无法舒舒服服的睡觉啦!并且由于昨天买的羽毛球拍到了,所以下午是打羽毛球的快乐时光,所以该篇博客,今天能不能发,是未可知的!

学习系统编程No.20【进程间通信之命名管道】

回顾管道控制进程

之前开始学习进程间通信的时候,我们就学习了如何使用管道来进行进程间通信,了解了通过一个管道进行进程间通信之后,我们又通过管道的读写规则了解了"血缘关系"进程之间的通信方法,此时我们通过一个 很经典的通信方式(当管道中没有数据的时候,对应读取数据的进程只能等待对应写数据的进程) ,所以通过这一重要的读写原理,此时我们就设计出了进程控制的结构一个进程(常常是父进程)通过创建多个管道和子进程,然后向对应的管道中写入数据,进而控制与该管道文件匹配的子进程,所以明白了这个原理之后,此时就可以进行具体的编码和优化,最终得到了上篇博客所示的进程控制代码,但是该代码中,还存在一个很隐蔽的问题,上篇博客,我们没有进行详细的讲解,所以在这里,我们进行补充讲解,如下:

回收子进程

1.让子进程退出

从进程控制代码中(上篇博客),我们看出,当我们构建好了进程控制代码,可以让父进程通过对管道文件的读写规则同时去控制子进程完成不同的任务时,在最后任务完成结束,代码要退出时,我们是需要将子进程进行回收(因为子进程占用的是内存上的空间,避免内存泄露),所以此时在回收子进程的问题上,就存在那个很隐蔽的问题,此时我们就需要解决这个问题,如下:

想要解决这个问题,首先明白一点,就是如何让子进程退出,这点想必大家都很清楚(上篇博客详细介绍了),想要让一个子进程退出(场景:上篇博客代码,子进程读取管道文件,父进程向管道文件写入),只要让父进程无法向对应子进程的管道文件中写入数据,此时操作系统就会因为不允许资源浪费,使 用13号信号,让子进程退出,所以让一个子进程退出,就是将对应管道文件的写端关闭就行

明白了这点,此时我们距离解决这个隐蔽问题就剩下一个现象,看到了这个现象,此时一切都是So,So,如下图所示:
学习系统编程No.20【进程间通信之命名管道】

如上图所示,明白到了,除了第一次循环的子进程是只继承了一个写文件描述符,其它子进程的写文件描述符都是在累加,所以导致除了最后一次循环创建的那个管道文件的写端只有父进程指向之外(因为最后一次循环子进程为了构建单向信道,需要把写端关闭),其它的管道文件都被除了父进程以外的一个或多个进程以写的方式指向(如上图,第五次循环之后的子进程,此时对前面创建的4个管道文件的写端都有写入的能力),具体如下图所示:
学习系统编程No.20【进程间通信之命名管道】
所以上图的第一个管道文件的写端由于被不止一个进程打开,所以此时单单只是将父进程对应的写端关闭,还有剩下多个子进程可以向该管道文件写入数据,所以此时操作系统并不会使用13号信号,将该子进程退出,所以最好的解决方法就是如上图所示:
从后向前关闭父进程对应管道文件的写端,这样就可以让子进程挨个退出了,进而最终达到回收子进程的目的

有关上述现象图的继承理解
注意: 在常见的操作系统中,当子进程从父进程中继承文件描述符表时,子进程会得到指向同一文件表项的新的文件描述符副本(继承),关闭一个文件描述符只会减少该文件描述符所指向的文件表项的引用计数,如果仍然有其他文件描述符指向该文件表项,则该文件表项仍然存在;因此,无论父进程关闭其中的一个文件描述符或者两个,当子进程从它那里继承文件描述符表时,子进程都会得到对这两个打开文件的文件描述符

总结: 只要父进程分别以读写的方式打开了同一文件,创建了两个文件描述符,那么此时无论父进程是关闭一个文件描述符,还是两个都关闭,此时由于子进程继承了父进程pcb大部分的内容,并且因为进程间具有独立性,所以此时操作系统检测都父进程将要关闭文件描述符的时候(也就是修改数据的时候),就会进行写实拷贝(在内存中重新开辟一个空间给父进程去修改数据),所以导致子进程中继承的父进程pcb是不会被改变,所以子进程任然可以分别继承以读写方式打开的两个文件描述符

2.等待僵尸状态的子进程

明白了上述知识点之后,此时就可以明白除了最后一次循环创建的管道文件只被一个进程以写的方式打开之外,其它的管道文件都是同时被两个或者两个以上的进程以写的方式打开(父进程和子进程),所以最好的方法就是从后向前将父进程对应管道文件的写端关闭,此时所有的子进程就被很好的关闭了,所以当子进程被关闭之后,此时最后一步就是将处于僵尸状态的子进程回收(waitpid),具体代码如下:
学习系统编程No.20【进程间通信之命名管道】
具体现象如下:
学习系统编程No.20【进程间通信之命名管道】
学习系统编程No.20【进程间通信之命名管道】
所以此时因为进程控制创建出的被控制进程和创建的管道文件就都被关闭和回收啦!利用管道控制进程的代码就大功告成啦! 具体代码贴在该博客最后(虽然上篇博客中有)

深入进程控制结构

通过上述的知识,我们知道,我们可以很好的利用进程间通信的知识和模板去构建出一个进程控制的结构,并且这个结构中存在的问题(上述问题),因为子进程会继承上一进程打开的所有文件描述符,导致一个子进程同时具有多个读端和写端,此时根据这个现象,就会存在很多的问题,不仅仅只是上述回收子进程的时候需要从后向前回收,更重要的是 ,此时还有引起另一个严重问题,就是后一个子进程也可以向前一个管道文件中写入数据,有甚者更是可以向多个管道文件中写入数据(虽然因为没有特定的文件描述符,子进程并不能写入,但是为了防止),所以需要避免这个问题,此时我们就可以通过将代码结构进行一定的改变,进而真正的构建出像进程间通信一般的单向信道,如下:

原理:本质上,在实现上述进程控制的前提下,让每一个管道和进程之间都互不干扰,实现单向通信是不难的,实际从问题出发,就是要解决子进程继承父进程文件描述符时,多余进程的文件描述符而已,所以此时我们只需要再创建一个数组,用这个数组专门来保存父进程创建的写端文件描述符,得到父进程所有的写端文件描述符,然后把这个数组中的数据拿给子进程使用,间接在子进程中遍历这个数组,并且使用close关闭子进程继承的文件描述符表中对应数组下标对应的写端文件描述符,这样子进程中多余进程到的写端文件描述符就被全部关闭,最终真正的实现单向信道进程控制结构

具体代码实现如下:
学习系统编程No.20【进程间通信之命名管道】

命名管道

无论是之前的进程间数据传送的知识,还是上述进程控制的知识,本质上都只是在利用管道进行而已,准确的来说也就是利用一个内存级的文件而已,并且要明白,此时的这个管道是使用系统调用接口 pipe 来创建的,所以本质上这个管道文件是操作系统给我们提供的,我们是摸不着,看不到的,所以准确的来说,我们之前学习的进程数据传送和进程控制利用的管道都是匿名管道,一个由内核创建,操作系统管理的文件

并且还可以得出一个结论,我们一直利用的都是具有"血缘关系"的进程可以继承同一文件描述符的特性和同时以读写方式打开同一匿名管道文件进行学习有关进程间通信的知识,此时提出问题:那么如果是两个完全没有关系的进程,此时进程间还可以进行通信吗?首先答案是可以的,不然它怎么能叫进程间通信呢?就应该叫血缘关系进程进程间通信了,具体如下述所说:

如何创建命名管道

首先明白,想要让两个不同的进程支持相互通信,那么此时就不可以使用匿名管道,而要用命名管道,所以下面第一个知识点,我们就来了解一下命名管道的创建,注意:命名管道的创建区别于匿名管道的创建,它不仅可以直接使用命令行创建,指令:mkfifo filename,也可以使用系统调用创建,调用接口:int mkfifo(const char *filename,mode_t mode);基本使用:mkfifo("filename", 0644);具体使用方式如下图所示:
学习系统编程No.20【进程间通信之命名管道】
通过上图中对 mkfifo 系统调用接口的描述,此时我们就可以知道,该接口的功能就是用来创建一个命名管道,头文件为#include<sys/types.h>,#include<sys/stat.h>等具体使用方式,此时我们就可以很好的自己创建一个命名管道出来啦!

注意: 虽然,mkfifo是创建一个文件,并且这个文件不像是匿名管道文件一样是由内核创建的内存级文件(不占用磁盘空间),并且该文件是位于文件系统中,但该文件却并不对应任何物理磁盘上的文件,而只是在内存中分配一个空间来存储不同进程之间进行进程间通信时的读取或写入的数据而已(类似于文件对象自带的缓冲区),所以从这个意义上来说,我们可以将mkfifo创建的文件视为一种内存级文件,因为它们的存在仅限于进程之间的通信,当进程间完成通信之后,回收进程时,此时由于它们的生命周期与它们关联的进程相同,所以当这些进程终止时,这些文件也会被自动删除,所以本质上命名管道文件就是一个内存级缓冲区文件!

得出结论: 使用 mkfifo 创建的文件并不会占用磁盘空间,因为它只是一个命名管道(内存级文件),只有在进程进行通信时,也就是一个进程打开一个命名管道并向其中写入数据,另一个进程打开同一个命名管道并从中读取数据,此时才会产生实际的数据传输和占用磁盘空间,否则执行 mkfifo 命令只会在文件系统中创建一个新的文件节点,并不会分配任何实际的磁盘空间

管道文件类型:
学习系统编程No.20【进程间通信之命名管道】
对文件类型和文件属性感兴趣的同学可以参考该链接博客:文件类型详解

文件类型
普通文件 -
目录文件 d
链接文件 l
块设备 b
字符设备 c
管道文件 p
套接字文件 s

深入命名管道

搞定了上述有关命名管道文件的知识,此时我们就可以具体的来看一看,是如何利用命名管道实现不同进程之间的通信了,如下图所示:
学习系统编程No.20【进程间通信之命名管道】
如上图所示:此时我们就构建出了一个和构建父子进程间通信结构类似的模板,此时按照这个原理,我们就可以进行代码的编写啦!简单理解就是两个进程打开了同一个文件,一个进程以读的方式打开,一个进程以写的方式打开,本质能够通信还是因为,操作系统为了节约资源,所有进程共享同一个已经打开的文件,而不是重复打开,并且 注意, 如果我们想要让不同的两个进程打开同一个文件,此时就需要让它们根据同一路径去寻找该对应文件**,所以只要让不同的进程通过文件路径和文件名看到同一文件,并打开,这就是两个不同进程看到同一份资源的前提,也就是进程间通信的前提!

代码实现

原理: 1.创建一个管道文件 2.让读写端进程分别按照自己的需求打开文件 3.开始通信

首先创建两个文件,一个serves.cpp,一个client.cpp,用来分别表示两个不一样的进程,具体代码如下:

serves.cpp文件

学习系统编程No.20【进程间通信之命名管道】
client.cpp文件

学习系统编程No.20【进程间通信之命名管道】

command.hpp共享文件

学习系统编程No.20【进程间通信之命名管道】
两个进程代码通信现象:
学习系统编程No.20【进程间通信之命名管道】
如上图所示,此时一个进程就可以很好的把数据传送给另一个进程,也就类似于一个用户端可以把数据传送给服务端

总:明白了使用匿名管道的进程控制,玩一个命名管道So,So!

学习系统编程No.20【进程间通信之命名管道】

总结:快乐生活每一天,有关管道的知识就这样了吧!

使用匿名管道进行进程控制代码如下:

学习系统编程No.20【进程间通信之命名管道】文章来源地址https://www.toymoban.com/news/detail-415752.html

到了这里,关于学习系统编程No.20【进程间通信之命名管道】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学习系统编程No.13【文件系统】

    北京时间:2023/3/31/7:48,该篇博客在两天前本就应该产出,但是摆烂谁拦得住,所以呜呜呜!本以为欠的钱也要快还完了,没想到啊,越欠越多,烦人!但是,欠的都是小钱,不像以前,欠的是大钱,所以也不怎么打紧,慢慢还啦!这周的榜估计是保不住了,具体还要看看周

    2023年04月15日
    浏览(72)
  • 学习系统编程No.24【深入学习信号】

    北京时间:2023/6/13/19:07,伴随着期末考的来临,最近停课啦!无论是线上课,还是学校的课,开心,那这不是咱持续更文的好时候嘛,但是今天在学习相关C++知识时,涉及到了线程相关知识,虽然能听,但是听起来就比较费劲,所以我们要先暂停C++相关知识的学习,转而投向

    2024年02月09日
    浏览(38)
  • 学习系统编程No.23【信号实战】

    北京时间:2023/4/23,最近学习状态不怎么好,总是犯困,没精力的感觉,可能是病没有好彻底的原因,也可能是我内心因为生病而认为摆烂理所应当,反正最后导致摆烂,课现在越来越跟不上了,并且刚刚蓝桥杯出成绩了,我肯定不是帮我自己看的,好奇看看而已,哈哈哈!

    2024年02月03日
    浏览(42)
  • 学习系统编程No.17【vscode实战】

    北京时间:2023/4/11/7:25,昨天11点洗澡,洗完直接睡,导致现在头发愈发不能看,So,平头时刻将要来临,头发太长真的很不方便,昨天已经更文啦!这个星期一定要实现日更,因为我发现,不日更,或者说更文不积极,根本上不了热榜,所以今天又有新文章和大家见面哦!

    2023年04月14日
    浏览(86)
  • 学习系统编程No.14【动静态库】

    北京时间:2023/4/3/7:06,刚刚晨跑回来,为了摆脱困意,刷了一下视屏,哈哈哈!我发现我每次刷视屏都是被迫的,都是看到某个感兴趣的标题,然后点进去一看,就不能自拔了,所以我下次得把消息提醒给全部关掉,烦人;并且全宿舍英文4级都报上了,就我没报上,真的是

    2023年04月09日
    浏览(54)
  • 学习系统编程No.33【生产消费模型】

    北京时间:2023/7/22/14:27,现实和预期往往相差是巨大的,哈哈哈!白天睡不醒,晚上睡不着,就像一个夜猫子一样。熬夜耍手机,我真的是专业的,已经连续好久没有正常睡过觉了。怀念学校里的日子,每天都有人激励我早睡和早起,此处@谢xx,不知他最近的学习状态如何,

    2024年02月14日
    浏览(38)
  • 学习系统编程No.32【线程互斥实战】

    北京时间:2023/7/19/15:22,昨天更新完博客,和舍友下了一会棋,快乐就是这么简单,哈哈哈!总体来说,摆烂程度得到一定的改善,想要达到以前的水准,需要一定的契机,毕竟人生在世,快乐最重要是吧!更文带给我的快乐已经没有那么多了,虽然欠了非常多的作业,非常

    2024年02月16日
    浏览(38)
  • 学习系统编程No.25【核心转储实战】

    北京时间:2023/6/16/8:39,实训课中,大一下学期最后有课的一天,还有两天就要期末考啦!目前什么都还没有复习,不到星期天晚上,咱不慌,小小挂科,岂能拦得住我补考,哈哈哈!小事,莫慌,该篇博客出炉之时,就是我复习之日,临阵磨枪不快也光,这方面我是专业的

    2024年02月11日
    浏览(46)
  • 学习系统编程No.12【基础IO】

    北京时间:2023/3/28/7:19,周二,早八的一天,难过!终于进入C站周创作榜啦!开心!给大家推荐一首歌《盛夏的果实》,给我的感觉非常的放松,劳逸结合,音乐非它莫属,为了下周周榜可以继续前进, 今天我们就来学习一下基础IO的知识吧! 从上篇博客,我们明白,重定向

    2023年04月21日
    浏览(55)
  • 学习系统编程No.26【信号处理实战】

    北京时间:2023/6/26/13:35,昨天12点左右睡觉,本以为能和在学校一样,7点左右起床,设置了7点到8点30时间段内的4个闹钟,可惜没想到啊,没醒,直接睡到了12点,看来下次不能给自己太高的期望,哈哈哈!在家没办法呀,习惯睡到12点了,想要解决这个问题,最好的方法就是

    2024年02月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包