进程间通信(IPC)

本文深入探讨了进程间通信的目的、方式和分类,重点讲解了匿名管道和命名管道的实现及特点。匿名管道适用于有血缘关系的进程通信,而命名管道则能实现非关联进程间的通信。此外,还详细介绍了共享内存的创建、关联和去关联过程,强调了其在不同进程间共享资源的能力,但需要额外的同步和互斥机制来保障安全。
摘要由CSDN通过智能技术生成


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

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

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

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

(2)如何做到呢?

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

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

 

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

 

(3)通信的分类;

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

② system V

③POSIX进程间通信


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

(1)什么是管道?

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

  

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

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

#include <unistd.h>
创建无名管道
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<sys/types.h>

#include<sys/stat.h>

 int mkfifo(char* pathname,size_t mode) 

看到同一份comm.h 

完成通信;

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

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

 

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

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

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

 

③拷贝文件;

 

 

 

 

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


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

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

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

 


(五)system V共享内存; 

(1)原理

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

 ​​​​​​

(2)建立过程;

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

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

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

(3)共享内存创建!

 ①创建共享内存;

#include<sys/ipc.h>

#included<sys/shm.h>

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

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

参数;

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

size:共享内存容量

shmflg;选项

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

     IPC_EXCL单独使用无意义~

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

②获取一个key;

#include<sys/types.h>

#include<sys/ipc.h>
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<sys/ipc.h>

#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds* buf)

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

 

(4)共享内存关联;

①关联

#include<sys/types.h>
#include<sys/shm.h> 

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);

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

祝你好运~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值