• 进程间通信(IPC)



     (一)进程间通信的理解;

     对进程间通信的理解,我们分为三个问题;

    (1)进程间通信的目的;

    数据传输:一个进程需要将它的数据发送给另一个进程.
    资源共享:多个进程之间共享同样的资源.
    通知事件:一个进程向另一个或一组进程发送消息.通知它发生了某种事件
    进程控制;进程知道另外一个进程的运行状态. 

    (2)如何做到呢?

    我们从进程的概念所知,如果仅仅依靠两个进程发生通信,是很难的。因为进程运行 具有独立性!

     进程A---->"拷贝"资源给OS(提供一段内存区域)---->OS“拷贝”资源---->进程B

     

    因此,通信的本质就是;  不同的进程看到,同一份资源 ;

     

    (3)通信的分类;

    ①管道:匿名管道  命名管道

    ② system V

    ③POSIX进程间通信


    (二)进程间如何进行通讯(匿名管道) 

    (1)什么是管道?

    管道是Unix中最古老的进程间通信的形式。
    我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
    且管道是允许  单向通讯

      

     (2)匿名管道(无文件名);

    因为把文件写到磁盘效率太低,所以通信管道会在内存中就进行通信。成为内存文件

    #include
    创建无名管道
    int pipe(int fd[2])

     (3)如何使用匿名管道?  ​

     

    根据文件描述符使用规则,系统在打开文件的时候,会默认打开三个流0,1,2。

     这个原理也就不多赘述。

    ①管道搭建;

     

     

     ②读和写入管道数据;

     

    (4)如何理解?

    ①写时拷贝与管道文件

     

    ②管道自带的同步与互斥;

    因此,是因为子进程写得慢,导致父进程需要等待(被阻塞) 子进程进行写入。----->同步+互斥 

     此时让写端停止写入,读端也就读不到数据A(挂起)

     

    当写端的管道写满 也就不会再写入(挂起)

     

    所以当我们把读端关闭掉,那么写端是否还能继续写入呢?

    答案是不可能!操作系统会自动把该进程杀掉!-------->写入无意义

     

      

    ③管道大小; 

    ulimit -a 查看系统资源

     

    所以管道大小就是65536

    ④管道特性+情况总结;

    特征:

    1.如果写端关闭,读端也就会读到0 | 

    2/如果打开文件的进程退出了,文件也会被释放掉。(文件的生命周期随进程).

    3.管道提供流式服务

    4.自带的同步与互斥

    5.半双工通信. 

    6.匿名管道适合血缘关系的进程进行通信.

    情况:

    read --->数据区没数据

    write-->数据区填满

    write时 read被关闭 此时会被操作系统干掉。

    write写完 关闭,read 返回值0;


     

     (三)进程间通信(命名管道)

    刚刚的管道的槽点,就在于需要相关的进程才能进行通信。但实际中大多数都是 非关联的进程巨多~

    (1)命令行形式

    命令行;

    mkfifo + filename;

    借用命名管道 重定向 通信;

     


     (2)函数mkfifo;

    #include

    #include

     int mkfifo(char* pathname,size_t mode) 

    看到同一份comm.h 

    完成通信;

     值得注意的是,因为两个进程通信的数据是存在管道缓冲区中,并没有刷新到磁盘里。

    所以命名管道并没有任何 变化。

     

    ②用命名管道发送 命令信号

    我们还可以借用命名管道做其他事情>

    自动去 启动这些命令的 进程。 

     

    ③拷贝文件;

     

     

     

     

    所以,进程间通信的意义在于,让多个进程协同完成同一件事情~ 


    (四)命名管道与匿名管道;

    我们linux中的 | 匿名管道还是命名管道?

     说明三个进程 ppid都是同一个! 所以有血缘关系。因此 这是 匿名管道!!

     


    (五)system V共享内存; 

    (1)原理

    想尽一切办法让不同进程,看到同一份资源。

     ​​​​​​

    (2)建立过程;

    1.申请共享内存(目前就这样认为)

    2.挂接共享内存(映射到进程的 地址空间里)---->已经达到看到同一份资源
    3.去关联(取消映射)

    4.释放空间(还给系统)

    (3)共享内存创建!

     ①创建共享内存;

    #include

    #included

    int shmget(key_t key,size_t size,int shmflg);

    (内存句柄)--->用户层的 共享内存接口~!

    参数;

    key:标定共享内存 唯一的标志!

    size:共享内存容量

    shmflg;选项

    注;IPC_CREAT 存在返回该共享内部 || 反之创建一个新的共享内存

         IPC_EXCL单独使用无意义~

         IPC_CREAT | IPC_EXCL(组合) ---->调用成功 获得一个新的共享内存。

    ②获取一个key;

    #include

    #include
    key_t ftok(const char* pathname,int proj_id)

    参数:

    pathname:路径名

    id:工程id

    单纯把id+pathname通过算法 生成一个序号~

    获取key值;

     

     管道是文件,不容易查它的容量。但是共享内存可以查到

    ipcs -m //查看

     当进程退出,这个共享内存是否还存在?

    这又说明什么呢? 

    管道;当进程退出时,管道也就不复存在。是随管道。

    共享内存:当进程退出时,不会销毁。是随内核。(再次论证,是由OS掌控)

    ipcrm -m + shmid //删除

     所以 key 与 shmid 的关系 类似于文件的

              fd         FIEL*

           内核层    用户层

     

    ③函数实现移除;

    #include

    #include
    int shmctl(int shmid,int cmd,struct shmid_ds* buf)

    1. //这里可以 写一下 监控脚本
    2. while :; do ipcs -m ; echo "##################" ; sleep 1 ;done

     

    (4)共享内存关联;

    ①关联

    #include
    #include 

    void* shmat(int shmid,const void* shmaddr,int shmflg);  

    参数:

    shmid;链接共享内存

    shmaddr;挂接哪个区域(本质上由操作系统完成)

    shmflg;默认设置(读和写)

    如何理解返回值?(void*)

    这是对应共享内存 映射到虚拟地址的起始地址!

    ~= malloc(同样也是返回申请内存的起始地址)

    如何理解挂接?

     

     

     

    ②去关联

    int shmdt(const void* shmaddr);

     

     

    (5)共享内存大小(size) 

    我们把size改为4097;

     

     

    其实本质上不是,你要申请开 大小的空间,就给你好多大小的空间。

    也就是说size 会被取整成 PAGE_SIZE(4096 byte)=一页数据!

     所以,我们虽然得到4097的空间显示,但事实上得到的是 2页匡空间!

    (6)实现通信; 

     

     

     我们首先一个打印A~z字母的打印;

     

    管道与共享内存的反思; 

     

    反观共享内存,就不会存在拷贝的概念。因为这段代码 由进程共享。 

    但有一个缺点,不提供任何保护机制(没有同步和互斥!!!)------->需要使用信号量提供保护


     

    总结;

    ①进程间通信的三种方法; 管道+共享内存(本质是让不同进程看到同一份资源);

    ②匿名管道pipe  "|",针对具有血缘关系的进程。

    ③命名管道 mkfifo+file_name mkfifo(file_name);

    ④共享内存完成的 是不同进程,通过进程地址空间+页表 映射了物理内存的一块共享区域。

    看到同样一份资源

    四部过程;申请共享内存(shmget) 挂接空间(shmat) 去关联(shmdt) 释放空间(shmctl);

    本篇就到这里啦,感谢你的阅读!

    祝你好运~

  • 相关阅读:
    【Jquery-04】jq中的属性操作
    GIRAFFE学习笔记
    SpringBoot接入轻量级分布式日志框架(GrayLog)
    刷题笔记19——优势洗牌和去重保持字典序
    Echarts图表 多表联动及图表数据还原
    【故障公告】没有龙卷风,k8s集群翻船3次,投用双集群恢复
    【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(8 月 25 日论文合集)
    微信小程序左滑删除(Slideview)
    数组趣味玩法:在Java SE中尝试创新玩法
    【Git】gitignore不生效场景2: 添加文件忽略 & .gitignore,整个文件夹都被忽略了
  • 原文地址:https://blog.csdn.net/RNGWGzZs/article/details/126169978