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

Linux_进程间通信_共享内存

什么是共享内存?

对于两个进程,通过在内存开辟一块空间(操作系统开辟的),进程的虚拟地址通过页表映射到对应的共享内存空间中,进而实现通信;物理内存中的这块空间,就叫做共享内存。

共享内存的优缺点

优点:方便、接口简单、加快程序效率、不要求进程有“血缘”关系。

缺点:没有提供同步机制,需要借助其他手段进行进程间同步工作。

           共享内存可以快于消息传递,但有高速缓存一致性问题。

 shmget函数

功能:用来创建共享内存

参数:

  •         key_t key:一个键值,用于唯一标识一个共享内存段。由用户输入,不能由内核自主生成。若由内核生成,则会导致两个进程看不到同一块共享内存。你可以使用IPC_PRIVATE常量创建一个私有共享内存段,或使用ftok()函数根据文件路径生成一个唯一的键值。
  •         size_t size:共享内存的大小,以字节为单位。
  •         int shmflg:标志位,用于控制创建和获取共享内存的行为。

                IPC_CREAT:若指定的共享内存不存在,创建并返回;若已存在,获取并返回。

                                        即保证调用进程能拿到共享内存。
                IPC_CREAT | IPC_EXCL:若共享内存不存在,创建并返回,若已存在,出错并

                                        返回。即只要成功,拿到的一定是新的共享内存(不拿旧的)!

  • 返回值:成功时返回共享内存的标识符(一个非负整数),失败时返回-1。
// Comm代码模块
const std::string gpath = "/home/ubuntu/112/linux/lesson24-fifo";
int gprojId = 0x6666;
int gshmsize = 4096;
// Server代码模块
int main()
{// 1. 创建keykey_t k = ::ftok(gpath.c_str(), gprojId);if(k == -1){ perror("ftok errror: ");}std::cout << "k : " << ToHex(k) << std::endl;// 2.创建共享内存 && 获取int shmid = ::shmget(k, gshmsize, IPC_CREAT | IPC_EXCL);if(shmid < 0){std::cerr << "shmget error" << std::endl;return 2;}std::cout << "shmid: " << std::endl;return 0;
}

共享内存的管理指令(指令释放)

  • ipcs :查询所有的system V通信方式

  • ipcs -m :查询共享内存

这里的key值与上面查询的是一样的。

  •  ipcrm -m shmid:删除共享内存

删除共享内存之后,再运行server就成功了

shmid vs key
  1. shmid:只给用户用的一个标识shm的标识符
  2. key:只作为内核中,区分shm唯一性的标识符,不作为用户管理shm 的id值 

 共享内存的管理函数(代码释放)

shmctl函数

功能:用于控制共享内存原型

参数:

        shmid:由shmget返回的共享内存标识码

        cmd:将要采取的动作(有三个可取值)              

        buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

 在上面代码的基础上,加上下面这句代码即可完成代码实现删除共享内存

shmctl(shmid, IPC_RMID, nullptr);

 ftok函数

在shmget函数中我们说到参数key是唯一的且是由用户输入的,但是用户有没有可能设置的key有冲突呢?答案是肯定的。所以,基于这个问题,我们引入了ftok函数。你只要给我一个公共的路径和一个公共的项目ID,我就会依据算法生成一个唯一值。虽然这样也有可能造成冲突,但是冲突的几率特别特别小!

// Comm模块代码
const std::string gpath = "/home/ubuntu/112/linux/lesson24-fifo";
int projId = 0x6666;
// Client / Server模块代码
#include <iostream>
#include "Comm.hpp"
int main()
{key_t k = ::ftok(path.c_str(), projId);if(k < 0){std::cerr << "ftok error" << std::endl;return 1;}std::cout << "k: " << k << std::endl;    return 0;
}

如果ftok函数返回失败时,我们就需要不断的尝试,对路径名和id值进行修改,直至成功。一般来说,有几种可能:

  • 如果传入的路径名不存在
  • 传入的路径名没有读取权限,无法读取该文件的索引节点号
  • 文件的索引节点超过了8位,即超过了一个字节的范围
  • 系统中已经使用了所有的IPC键值

shmat函数 

功能:将共享内存段连接到进程地址空间原型(关联)

参数:

shmid:共享内存标识

shmaddr:指定连接的地址

shmflg:是一组按位OR(或)在一起的标志,用来控制读写权限等。它的两个可能取值是SHM_RND和SHM_RDONLY。若取值为SHM_RDONLY,则以只读方式连接此段,否则以读写的方式连接此段。

返回值:成功返回一个指向共享内存起始地址的指针;失败返回-1

说明:

  1. shmaddr为NULL,核心自动选择一个地址
  2. shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
  3. shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
  4. shmflg = SHM_RDONLY,表示连接操作用来只读共享内存
void* ret = shmat(shmid, nullptr, 0);// 将共享内存挂接到自己的地址空间中

 注意:共享内存也有权限!

shmdt函数

功能:将共享内存段与当前进程脱离原型(去关联)

参数:

shmaddr: 由shmat所返回的指针

返回值:成功返回0;失败返回-1

注意:将共享内存段与当前进程脱离不等于删除共享内存段

::shmdt(ret);    // 去关联

shmdt的参数就是shmat的返回值。

共享内存的特点

优点

  • 高效性:
  1. 共享内存是IPC通信中传输速度最快的通信方式。因为数据不需要在客户机和服务器之间拷贝,数据可以直接写到内存,避免了多次数据拷贝,从而大大提高了通信效率。
  2. 进程对共享内存的访问就如同访问自己的内存空间一样,不需要进行额外的系统调用或内核操作,进一步提升了效率。
  • 灵活性:
  1. 允许多个进程共享数据,提供了一种灵活的通信方式。
  2. 进程间可以通过共享的内存区域进行双向通信,满足了多种通信需求。
  • 支持大量数据传输:
  1. 适用于需要快速传递大量数据的场景,特别是在大数据处理、实时通信等领域表现突出。

缺点 

  • 具有同步相关的问题:

因为多个进程可以同时访问共享内存,因此需要额外的同步机制来避免 数据不一致性 问题。内核中并不提供任何对共享内存访问的同步机制,因此通常需要使用信号量等其他IPC机制进行读写同步与互斥。(例:写端要向共享内存中写入hello world,但只写了hello,读端就读走了)

  • 安全性

需要额外的安全机制来保护数据,防止其他进程非法访问。若未采取适当的安全措施,可能导致数据泄露或被篡改。

  • 编程复杂性

使用共享内存进行通信需要处理同步和数据一致性等复杂问题,编程复杂度较高。需要开发者具备深厚的操作系统和并发编程知识。

  • 依赖操作系统支持

共享内存的使用依赖于操作系统的支持。不同的操作系统或版本可能对共享内存的实现和管理方式存在差异,这增加了跨平台开发的难度。

http://www.lryc.cn/news/519108.html

相关文章:

  • ubuntu 下生成 core dump
  • 学习HLS.js
  • 2025年华为OD上机考试真题(Java)——判断输入考勤信息能否获得出勤奖
  • 空对象模式
  • 开启Excel导航仪,跨表跳转不迷路-Excel易用宝
  • 年度技术突破奖|中兴微电子引领汽车芯片新变革
  • Ubuntu 如何查看盘是机械盘还是固态盘
  • 计算机网络(三)——局域网和广域网
  • STM32F4分别驱动SN65HVD230和TJA1050进行CAN通信
  • 将光源视角的深度贴图应用于摄像机视角的渲染
  • docker一键安装脚本(docker安装)
  • 【SY2】Apollo10.0 Cyber基于Writer/Reader的通信方式
  • 【YOLOv8杂草作物目标检测】
  • 在Java中实现集合排序
  • el-descriptions-item使用span占行不生效
  • Android 绘制学习总结
  • Linux下部署SSM项目
  • 计算机网络 笔记 数据链路层 2
  • xml简介
  • 透明部署、旁路逻辑串联的区别
  • 【网络安全渗透测试零基础入门】之XSS攻击获取用户cookie和用户密码(实战演示)
  • c#版本、.net版本、visual studio版本之间的对应关系
  • 熵与交叉熵:从不确定性角度理解 KL 散度
  • Redis:数据类型
  • 搭建Node.js后端
  • 集合——数据结构
  • 从CentOS到龙蜥:企业级Linux迁移实践记录(系统安装)
  • 《机器学习》——支持向量机(SVM)
  • 【PPTist】公式编辑、插入音视频、添加动画
  • LeetCode - #186 翻转字符串里的单词 II(会员题)