本文介绍: 一般的操作系统,会有一个独立通信模块 —— 隶属于文件系统 —— IPC通信模块定制标准 —— 进程通信是有标准的 ——system V && posix。2.共享内存删除不是直接删除,而是删除进程物理地址映射关系,到映射链数为0的时候,才为真正的删除。1.key对应一个int,至于数字多少不重要,重要的是它的唯一性,能够不同进程执行唯一标识对应key都是面向系统内核的,id都是面向用户的。如果两个不同的进程,打开同一个文件时候,在内核中,操作系统打开几个文件

进程通信什么

两个或者多个进程实现数据层面的交互,通信是有成本的。

为什么要有进程间通信:

在现实中进程之间一定会存在

基本数据交互

发送命令

某种协同

通知

所以需要进程间通信

如何实现进程间通信

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

  2. 资源”:特定形式的内存空间

  3. 资源”谁提供?操作系统,如果由进程之间提供会破坏进程之间的独立性

  4. 进程访问这个空间本质就是访问操作系统

  5. 基于文件级别通讯方式 ———— 管道

一般的操作系统,会有一个独立的通信模块 —— 隶属于文件系统 —— IPC通信模块定制标准 —— 进程通信是有标准的 ——system V && posix

管道

管道原理

管道原理进行通信的一定是具有血缘关系的进程:父子,兄弟,爷孙

对应父子进程都具有独立task_struct对应独立struct_file,但对应数组相同序号指向同一批文件:对应stdin,stdout,stderrno都是公用的:

如果父子进程想要创建自己的管道文件,对应一定是存在内存中而非磁盘中。

如何建立通信信道?

对应父子进程对同一个文件进行读写对应创建了通信。

对于父子进程来说,读写时文件的inode相同同一个文件缓冲区

不同fd执行不同操作,在不同的进程中存储

如果父子进程同时进行写入读取,那么对应的管道文件不是就乱了吗?

所以我们最好规定,一个进程读,一个进程写。

这也就注定了管道只能进行单向通信:

所以在struct_file中的引用计数就会起作用,对应有不同fd指向它,引用计数+1。

可以看到上面的内存文件(管道文件)没有名字,也对应叫匿名管道。

2.对应创建匿名管道文件的接口pipe

对应的头文件接口

对应参数数组两个元素一定是读方法和写方法。

注意接口使用

下面写代码验证

对应的运行结果

可以看到在012后面创建了两个文件:记住下标为0的是读,为1的是写。

接下来创建子进程让子进程写,父进程读:

看看字符串是否构建成功

可以看到构建成功了。

再向父进程写入

对应代码执行结果:

可以看到执行起来了。

下面来验证管道中的四种情况:

1.读写端正常,管道如果为空,读端就阻塞

2.读写端正常,管道如果被写满,写段就要阻塞

写满多大呢?修改代码来验证:

子进程一次写入一个字节

父进程不读:

对应代码结果:

最后一个值是6535,对应管道缓冲区大小位64KB。

3.读端正常,写段关闭,读端会读到0,表明文件结尾,不会阻塞

0:

修改代码

对应文件读完了。

可以看到后面n变为0,对应文件为空,所以我们要在文件读取是在加一个判断

对应的结果:

对应代码更完善。

4.写段写入正常,读端关闭操作系统通过信号干掉正在写入的进程。

代码:

对应获取子进程的退出码和退出信号

让父进程读5秒就停,子进程继续写对应结果:

对应的是pipe错误退出

对应让子进程写入,父进程读取,为了方便看到退出信号,对应就是操作系统终止了进程

管道的特征

1.只有具有血缘关系的进程才能进行管道通信

2.管道只能进行单向通行

3.父子进程是会进行协同的:解决临界资源竞争问题多线程

4.管道是面向字节流的(网络

5.管道是基于文件的,而文件的生命周期是随进程的。

细节

1.对应管道通信其实就是对应的缓冲区拷贝

写入是从用户内存读取是从内存用户

2.管道的固定大小是可以改变的

3.snprintf使用

管道的使用场景

1.自制shell支持管道(文件重定向),这里实现了,主要实现下一个

2.用管道实现一个简易版本的进程池:

进程池的概念

对应让父进程写,子进程读,都读相同大小内容,这样格式一样

对应可以实现一个简单游戏日志

将这些子进程管理起来,也是先描述,再组织

代码对应对子进程的描述

子进程初始化

对应先对初始化好的子进程打印一下:

main函数

对应代码的执行结果:

接下来让子进程执行一点有意义的东西:

注意对应输入输出函数对应的规范

输入const  &

输出:*

输入输出: &

定义一个头文件存放日志:

main函数初始化这个日志函数指针数组:

控制子进程:

菜单来对应要实现的功能.

子进程运行时候也要修改

执行对应的函数

对应退出函数关闭文件描述符等待子进程:

对应的结果:

对应没有问题

初始化bug:

命名管道:

上面的匿名管道都是具有血缘关系之间的进程的通行,那么如果没有血缘关系呢?

对应就是命名管道。

命名管道的理解

命名管道本质只是管道的一个标识,它不存在这块管道缓冲区还是存在的。

如果两个不同的进程,打开同一个文件的时候,在内核中,操作系统打开几个文件?

同一个文件。

对应的文件都是路径+文件名

对应的编码

对应的结果:

实现一个自己的日志:

共享内存

原理

主要分为三步:

1.申请物理内存

2.挂接到进程地址空间中。

3.返回起始虚拟地址

直接代码对应的系统接口

shmget:

对应返回值参数的含义:

创建K:

ftok:

key理解

1.key对应是一个int,至于数字多少不重要,重要的是它的唯一性,能够不同的进程执行唯一标识。

2.通过key创建共享进程

3.key存在共享内存描述对象

4.上面创建key函数的两个参数都是由用户自己约定的,

5.key 路径 唯一性

shmat:

将共享内存链接到对应的共享内存

shmdt:

脱离连接

shmctl:

用于控制共享内存这里是把它删掉

3.共享内存特性

1.共享内存没有同步互斥之类的保护机制

2.共享内存是所用进程中通信中,速度最快的。(拷贝少)

3.共享内存内部的数据由用户自己来维护shmid

共享内存的本质

1.开辟一块物理空间,让多个进程映射到同一块物理内存到自己的地址空间进行访问

2.共享内存的删除不是直接删除,而是删除进程与物理地址映射关系,到映射链数为0的时候,才为真正的删除

3.共享内存的生命周期是随内核的(本质是一块内存)。

只要不被删除就一直存在系统中。

消息队列信号量

1.将共享内存的接口消息队列接口进行比较

对应的get

接口基本相似

都有key所以都要用到ftok接口。

对应的ctrl接口:

接口的参数都相同,对应的最后一个参数需要自己创建结构体,自己传指针

对应描述结构体:

这里可以看到c语言继承的影子。

消息队列原理

就是让不同的进程看到同一个队列

A,B进程的发送方式都是以数据块的形式发送

发送的数据块必须是带类型的,不然就不知道是谁发送的。

进程间通信在内核中的数据结构设计

所有的IPC资源都是存在系统的IPC模块中的:

其中不同的通信方法都是对系统内存中一块空间的数据结构继承

对应的key都是面向系统内核的,id都是面向用户的。对应不同的通信方式都是存在同一个指针数组的。

学习信号量的储备知识

管道通信的不足:

1.AB看到同一份资源,如果不加保护,会导致数据不一致问题。

2.加锁互斥访问,对应任何时候,只允许一个执行流访问资源。

3.共享的,任何时候只允许一个执行流访问的资源叫临界资源。

解释一个现象:

多进程,多线程并发打印会导致:

显示器上的消息

信号量

本质

是一个计数器用来描述临界资源中资源数量的多少

原理概念

1.申请计数器成功了,就表示具有访问资源的权限了。

2.申请计数器资源是对资源的预订机制

3.计数器可以有效保证进入共享资源的执行流的数量

4.所以每个执行流访问共享资源不需进过计数器,不能直接访问

上面对应的“计数器”就是信号量

那么如果信号量对应的共享资源只有一个呢?

意味着只能有一个执行流来访问这个临界资源。

这样的信号量叫二元信号量,其实就是一个锁。

信号量的pv操作

p操作申请信号量,本质是对计数器的–

v操作:释放信号量,本质上是对信号量的++

两个概念

1.多个信号量:对应着多种不同的共享资源管理

2.信号量是几:对应共享资源在信号量中的几号位

信号量凭什么也是通信的一种?

  • 通信不仅仅是通信数据,互相协同也是

  • 协同本质也是通信,信号量要被所用要通信的进程看到。

信号量的接口太复杂这里不看了。

原文地址:https://blog.csdn.net/m0_61497245/article/details/134802558

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45470.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注