当前位置: 首页 > news >正文

linux系统之----共享内存

1.什么是共享内存

共享内存(Shared Memory)是操作系统提供的一种 最高效 的进程间通信(IPC)机制。它允许多个进程 直接访问同一块物理内存区域,无需通过内核中转数据,从而避免了数据拷贝,速度极快。

2.共享内存原理

这里结合老师的图片来理解一下,可以简单理解为操作系统开一块内存区域作为共享内存,这块内存区域可以被多个进程访问,之后两个进程(进程A和进程B)通过页表将共享内存映射到自己的虚拟地址空间。这意味着每个进程都有一个虚拟地址,指向同一块物理内存。最后当所有进程都不再需要共享内存时,操作系统会回收这块内存。

3.创建共享内存

这里我们要介绍一个函数shmget,

这里我们先解释一下shmget函数里面的三个参数

  1. key

    • 这是一个 key_t 类型的值,用于标识共享内存段。它可以是一个特定的值,也可以是 IPC_PRIVATE,后者会创建一个私有的共享内存段,不能被其他进程访问,除非它们明确知道这个段的标识符。

  2. size

    • 这是共享内存段的大小,以字节为单位。这个大小必须与系统页面大小对齐,通常是 4096 字节的倍数。

  3. shmflg

    • 这是一个权限标志,用于设置共享内存段的访问权限。它通常是一个八进制数,由 IPC_CREAT(如果不存在则创建共享内存段)、IPC_EXCL(与 IPC_CREAT 一起使用,如果共享内存段已存在则失败)和一组权限位(如 06660644)组成。

我们看一下原文:

补充说明一些内容:

(1)

IPC_CREAT单独:如果创建的共享内存不存在,创建之。如果存在,直接获取它

IPC_EXCL:不能单独使用没有意义

IPC_CREAT | IPC_EXCL:如果共享内存不存在 创建之,如果已经存在 出错返回!

如果成功,返回的就是全新的shm!

(2)

这个key值是用户自己传入的,也许有人会疑惑为什么要用户自己传入呢?原因就是要保证唯一性:即key 值用于在系统中唯一标识一个共享内存段。如果两个进程想要访问同一个共享内存段,它们需要使用相同的 key 值来引用它。手动传入 key 值可以确保进程能够找到正确的共享内存段。如果系统自动生成 key 值,可能会在不同的进程或会话中生成相同的 key 值,从而导致冲突。

那么用户是如何得到Key值的呢?这里就要引入另外一个函数ftok()

4.key值的获取

我们看一下ftok函数的细节:

那这个函数是如何保证产生的Key值是相同的呢?原因就是在一个文件下,假设我定义如下便变量:

char* pathname="/tmp";
int pro_id=0x66;

那么,既然函数传的参数都是一样的,那返回值也一定是相同的,如此,我们得到了这个相同的Key值,之后再将它传入shmget函数中!

5.映射

现在我们已经拿到共享内存了,那么下一步便是将共享内存段映射到进程的地址空间,即shmat函数(shared memory attach)

参数说明

  1. shmid

    • 这是共享内存段的标识符,由 shmget 函数返回。它是一个非负整数,用于唯一标识一个共享内存段。

  2. shmaddr

    • 这是一个指针,指定共享内存段在进程地址空间中的首选映射地址。通常设置为 NULL,表示让系统选择一个合适的地址。

  3. shmflg

    • 这是一个标志,用于控制共享内存的映射属性。它可以是以下值的组合:

      • SHM_RDONLY:将共享内存段映射为只读。

      • SHM_RND:将共享内存段映射到一个由 shmaddr 参数指定的地址的某个倍数。

      • IPC_CREAT:如果共享内存段不存在,则创建它(通常与 shmget 函数一起使用)。

6.脱离

如果我们想解除(或分离)共享内存段与进程地址空间之间映射关系,那么我们可以用shmdt函数

  1. shmaddr

    • 这是一个指针,指向之前通过 shmat 函数映射到进程地址空间的共享内存段的起始地址。

注意事项

1)解除映射后,进程将不再能通过原来的地址访问共享内存。如果需要再次访问,必须重新映射。

2)shmdt 函数不会删除共享内存段。共享内存段仍然存在于系统中,直到所有映射它的进程都解除映射,并且通过 shmctl 函数显式删除。

3)在多线程环境中,如果多个线程访问同一个共享内存段,每个线程都需要调用 shmdt 来解除映射。

7.控制

如果我们想控制共享内存段的 System V IPC(进程间通信),可以用shmctl函数,它提供了多种操作,包括获取共享内存段的信息、删除共享内存段等。

  1. shmid

    • 这是共享内存段的标识符,由 shmget 函数返回。它是一个非负整数,用于唯一标识一个共享内存段。

  2. cmd

    • 这是一个命令,指定对共享内存段执行的操作。常见的命令包括:

      • IPC_STAT:获取共享内存段的状态信息,并将结果存储在 buf 参数指向的结构中。

      • IPC_SET:设置共享内存段的权限和所有者信息,使用 buf 参数指向的结构提供新值。

      • IPC_RMID:删除共享内存段,释放所有相关资源。

  3. buf

    • 这是一个指向 shmid_ds 结构的指针,用于存储或设置共享内存段的状态信息。具体使用取决于 cmd 参数的值。

注意事项

使用 IPC_RMID 删除共享内存段时,需要确保所有进程都已解除映射(通过 shmdt 函数)。

8.比较key和shmid

key vs shmid

key:只有内核使用,用来标识shm的唯一性,是用于查找或创建 IPC 资源的关键字,它是一个抽象的概念,用于标识资源

shmid:给用户使用,用来进行访问shm,shmid 是由操作系统分配的,用于唯一标识一个共享内存段的整数。它是具体的,用于操作系统内部管理和操作共享内存段。

接下来我们再用共享内存的知识写一下客户端和服务器那个小项目~

http://www.dtcms.com/a/360028.html

相关文章:

  • 开学季,音频格式古诗词,也可作为启蒙教育。
  • C#异步编程
  • OpenCL C++ 内核(Kernel)
  • 【动态规划】回文串问题
  • linux修改权限命令chmod
  • 借助 Kubernetes 与 vLLM 实现大规模大语言模型推理
  • 使用Cadence工具完成数模混合设计流程简介
  • uvm do on
  • 【深度学习】配分函数:近似最大似然与替代准则
  • Python毕业设计推荐:基于Django+MySQL的养老社区服务管理系统
  • Spring —— 数据源配置和注解开发
  • 【IDE问题篇】新电脑安装Keil5,出现找不到arm 编译器版本5编译报错;改为版本6后旧代码编译是出现编译报错
  • 通过编辑Offer Letter源代码实现批量修改
  • 刚上线的PHP项目被攻击了怎么办
  • Java全栈开发面试实战:从基础到微服务的全面解析
  • 策略模式:模拟八路军的抗日策略
  • 【Java后端】SpringBoot配置多个环境(开发、测试、生产)
  • LangChain框架深度解析:定位、架构、设计逻辑与优化方向
  • Mysql什么时候建临时表
  • 【机器学习基础】监督学习算法的现代理解:从经典方法到无人驾驶与生成式AI的实践应用
  • 柔性数组与不定长数据
  • SpringAI应用开发面试全流程:核心技术、工程架构与业务场景深度解析
  • KingbaseES V009版本发布:国产数据库的新飞跃
  • 嵌入式学习笔记--Linux系统编程--DAY04进程间通信-信号
  • 【Java学习笔记】18.Java数据库编程 - 1
  • 基于Echarts+HTML5可视化数据大屏展示-惠民服务平台
  • AG32 Nano开发板的烧录与调试工具
  • react-beautiful-dnd ​React 拖拽(Drag and Drop)库
  • 网格dp|
  • 机器视觉opencv教程(三):形态学变换(腐蚀与膨胀)