Linux_共享内存通信

目录

1、共享内存原理

2、申请共享内存

2.1 ftok 

2.2 测试shmget、ftok 

2.3 查看系统下的共享内存 

3、关联共享内存

3.1 测试shmat

4、释放共享内存 

4.1 测试shmctl 

5、实现共享内存通信 

6、共享内存的特性

结语 


前言:

        在Linux下,有一种进程间通信方式(IPC)名为共享内存,他是IPC中通信最快的方式(通信方式为全双工),因为他直接在物理内存上创建一块区域并且映射在进程的地址空间中,使得进程使用共享内存就如同直接使用动态申请的空间,因此通信过程少了内核的系统调用步骤,以至于相比于其他IPC模式速度更快,不过也正是因为在通信时不受内核管辖,导致共享内存不具备同步互斥机制,因此需要用户手动处理同步互斥问题。

        但是需要注意的是共享内存虽然使用起来如同动态空间,但是他的底层和动态空间不一样,动态空间具有独立性,只限于单个进程内部的访问,而共享内存允许多个无亲缘进程进行通信,因此他和动态空间是有区别的。

1、共享内存原理

        共享内存的目的就是为了进程间通信,而进程间通信的核心观念是让不同的进程看到同一份资源,所以共享内存必须在物理内存上开辟一块空间,并且映射到进程地址空间中的共享区,具体示意图如下:

        但是共享内存的申请和malloc申请是不一样的,因为共享内存要面向所有进程,要做到这一点就必须调用系统接口,所以要进行共享内存通信必须调用系统接口。

2、申请共享内存

        在物理内存上申请共享内存的接口是shmget,该接口介绍如下:

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
//key是用户给这段共享内存设置的名字,一个key对应一个共享内存
//size表示申请共享内存的大小
//shmflg表示权限设置,常用的有IPC_CREAT和IPC_EXCL//调用成功返回非负整数表示共享内存的标识码(给系统看的),失败返回-1

        着重介绍shmflg:

        1、当传递的是IPC_CREAT|IPC_EXCL,表示若以当前key值申请的共享内存不存在,则创建一个并返回新共享内存的标识码。若以当前key值申请的共享内存存在则返回-1,表示申请失败。

        2、当传递的是IPC_CREAT,表示若以当前key值申请的共享内存不存在,则创建一个并返回新共享内存的标识码。若以当前key值申请的共享内存存在则返回该共享内存的标识码。

        所以使用IPC_CREAT|IPC_EXCL可以判断一个key对应的共享内存是否存在,即key值是否被用过,当我们想用一段新的共享内存则可以使用IPC_CREAT|IPC_EXCL。

        key值的作用是判断两个进程的共享内存是否为同一个,两个进程所用的key一样说明他们共用同一个共享内存,反之则否,因此可以理解为key值是用户给一段共享内存起的名字,而shmget返回值是系统给这段共享内存起的名字。

2.1 ftok 

        shmget需要用到key值,key的类型虽然是key_t,但是也可以传一个int类型的值给到key,只不过这么做会导致潜在的重名风险,并且key的值需要程序员自己维护,于是系统提供了一个接口ftok,他像是一个算法,可以计算并返回一个key_t类型的值,该接口介绍如下:

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
//接收一个路径和一个整形
//成功返回一个key_t类型的值,失败返回-1

         所以两个进程调用ftok时传参是一样的,那么这两个进程就会获得相同的key值,这样两个进程就能看到同一份资源了,也就完成了通信的前提。

2.2 测试shmget、ftok 

         先用代码测试上述接口,测试代码如下:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <iostream>using namespace std;int main()
{const char *pathname = "/home/zh";int proj_id = 12;int size = 4096;key_t key = ftok(pathname, proj_id);if (key < 0){perror("ftok");return -1;}cout << "key值被成功创建,key:" << key << endl;int shmid = shmget(key, size, IPC_CREAT | IPC_EXCL);if (shmid < 0){perror("shmget");return -1;}cout<<"共享内存标识码被成功创建,shmid:"<<shmid<<endl;return 0;
}

        运行结果:

2.3 查看系统下的共享内存 

        共享内存不同于动态申请空间,动态空间的生命周期随进程。但是对于共享内存而言,若用户不主动释放共享内存,则共享内存会一直存活在系统中,他的生命周期随内核,即内核重启才会清理这些共享内存,在Linux下用指令ipcs -m查看当下系统的共享内存,测试如下:

        并且可以通过指令ipcrm -m shmid删除对应的shmid,测试如下:

3、关联共享内存

         上述接口shmget可以申请一块共享内存,但是申请到了不意味着就可以直接使用共享内存进行通信,要进行通信还要关联共享内存,关联共享内存的接口介绍如下:

#include <sys/types.h>
#include <sys/shm.h>//关联共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);
//shmid表示要关联的共享内存标识码
//shmaddr若不为NULL且shmflg不为SHM_RND,表示将共享内存的地址附加到shmaddr处
//shmaddr若为NULL,则该函数的返回值作为共享内存的地址(通常都设为NULL)
//shmflg表示权限设置,通常设为0表示对共享内存可读可写
//调用成功返回指向共享内存的指针,失败返回值(void*)-1//去关联
int shmdt(const void *shmaddr);
//让调用该函数的进程不再关联该共享内存
//shmaddr表示共享内存的地址

        总的来说,调用shmat关联共享内存后,会拿到一个执行该共享内存的指针,通过该指针就可以对共享内存进行读写操作。

3.1 测试shmat

        因为申请共享内存的代码后续会被重复使用,为了后续更好的测试,所以对申请共享内存的接口进行再一层封装,封装成sharemem.hpp文件,代码如下:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <iostream>
#include <unistd.h>using namespace std;const char *pathname = "/home/zh";
int proj_id = 12;
int size = 4096;key_t getkey()//封装ftok
{key_t key = ftok(pathname, proj_id);if (key < 0){perror("ftok");exit(-1);}cout << "key值被成功创建,key:" << key << endl;return key;
}int getshm(int shmflg)//封装shmget
{key_t key = getkey();int shmid = shmget(key, size, shmflg);if (shmid < 0){perror("shmget");exit(-1);}cout << "共享内存标识码被成功创建,shmid:" << shmid << endl;return shmid;
}int creatnewshm()//只想用最新的共享内存来进程通信
{return getshm(IPC_CREAT|IPC_EXCL|0666);//为了能够观察到变化,所以要保证共享内存的权限
}int getoldshm()//获取一个已经存在的共享内存进行通信
{return getshm(IPC_CREAT);
}

         后续的测试只需要包含该文件即可,测试shmat代码如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();cout<<"申请共享内存成功"<<endl;sleep(2);//观察nattch的值char* poi = (char*)shmat(shmid,NULL,0);cout<<"关联共享内存成功"<<endl;sleep(2);//观察nattch的值return 0;
}

        运行结果:

        其中,右侧nattch表示当前有多少个进程在关联该共享内存,当一个进程关联某个共享内存后,该共享内存的nattch+1,并且当该进程结束后,对应的nattch会-1。当然也可以使用shmdt手动去关联。

4、释放共享内存 

        手动释放共享内存的接口是shmctl,该接口本质的功能是控制共享内存,只不过也有删除选项,具体介绍如下:

#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//shmid表示要释放的共享内存的标识码
//cmd表示该函数执行的具体任务,比如IPC_RMID表示删除任务
//buf表示指向共享内存数据结构的指针,若使用删除任务则该指针置为NULL即可//调用成功返回0,失败返回-1

4.1 测试shmctl 

         测试shmctl的代码如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();cout<<"申请共享内存成功"<<endl;sleep(2);//观察nattch的值char* poi = (char*)shmat(shmid,NULL,0);cout<<"关联共享内存成功"<<endl;sleep(2);//观察nattch的值shmdt(poi);cout<<"成功去关联共享内存"<<endl;sleep(2);//观察nattch的值shmctl(shmid,IPC_RMID,nullptr);cout<<"成功删除共享内存"<<endl;return 0;
}

        运行结果:

        从结果可以看到,无论是去关联测试还是删除共享内存,在右边的监控中都会显示对应的效果。 

5、实现共享内存通信 

         有了上述的接口以及sharemem.hpp文件,就可以实现两个进程的通信了,所以需要写一个客户端进程和一个服务器进程,其中服务器进程创建共享内存,让他们两都关联该共享内存,并且由客户端向服务器发送消息,服务器代码如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();char *poi = (char *)shmat(shmid, nullptr, 0);cout << "关联共享内存成功" << endl;while (true){cout<<"服务器接收:"<<poi<<endl;sleep(1);}shmdt(poi);shmctl(shmid,IPC_RMID,nullptr);return 0;
}

        客户端代码如下:

#include "sharemem.hpp"int main()
{int shmid = getoldshm();char* poi = (char*)shmat(shmid,nullptr,0);cout<<"关联共享内存成功"<<endl;while (true){string message;cout<<"客户端发送:";cin>>message;strcpy(poi,message.c_str());}shmdt(poi);return 0;
}

        测试结果:

        从结果可以发现,共享内存的通信本质就是对一个空间进行内存式的访问,无需调用read、write这些系统接口,直接用内存函数写入数据至内存对方就能够读取到内存里的数据。

6、共享内存的特性

        1、共享内存不需要调用系统接口实现进程间通信,只需要调用内存函数对内存进行读写即可实现进程间通信。

        2、共享内存本身没有同步互斥的概念,体现在上面的运行结果中读端会一直读内容(说明没有同步),并不会因为写端还未写而阻塞住。并且读端和写端可以同时访问共享内存(说明没有互斥)。

        3、共享内存在读写效率上更为高效,因为少了write和read这些步骤,即少了一层拷贝。 

结语 

        以上就是关于共享内存通信的讲解,共享内存作为IPC的其中一种方式,相对于其他通信方式,他有利有弊,在实际应用里先熟悉他的接口以及使用共享内存的步骤:申请共享内存(包括创建key值)、关联共享内存(shmat)、去关联(shmdt)、释放共享内存(shmctl) ,通过以上步骤可以实现完整的共享内存通信。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爆!Java高级特性之Stream API详解

爆&#xff01;Java高级特性之Stream API详解 Java 8引入的Stream API可以说是一个革命性的特性,让我们告别了又臭又长的for循环,迎来了函数式编程的春天。今天就让我们来一起深入了解这个让人又爱又恨的Stream API吧! 什么是Stream? Stream就像一个高级的迭代器,允许我们以…

分支与循环

目录 1. if语句 1&#xff09;if 2) else 3&#xff09;分支中包含多条语句 4&#xff09;if嵌套 2.关系操作符 3.条件操作符 4.逻辑操作符&#xff1a;&& || ! 1) 逻辑取反运算符 !​编辑 2 与运算符​编辑 3) 或运算符​编辑 4) 闰年的判断 5) 短路 …

若依 Vue 前端分离 3.8.8 版中生成的前端代码中关于下拉框只有下拉箭头的问题

生成代码修改前 <el-form-item label"课程学科" prop"subject"><el-select v-model"queryParams.subject" placeholder"请选择课程学科" clearable><el-optionv-for"dict in course_subject":key"dict…

【博士每天一篇文献-算法】Adult neurogenesis acts as a neural regularizer

阅读时间&#xff1a;2023-12-20 1 介绍 年份&#xff1a;2022 作者&#xff1a;Lina M. Tran&#xff0c;Adam Santoro&#xff0c;谷歌DeepMind 期刊&#xff1a; Proceedings of the National Academy of Sciences 引用量&#xff1a;13 代码&#xff1a;https://github.c…

A4-C四驱高防轮式巡检机器人

在当今数字化和智能化迅速发展的时代&#xff0c;旗晟智能带来了一款革命性的创新产品——A4-C四驱高防轮式巡检机器人。这款机器人以其卓越的性能和多功能性&#xff0c;为工业巡检领域带来了全新的解决方案。 一、产品亮点 1、四驱动力与高防护设计 四驱高防轮式巡检机器人…

ASUS/华硕枪神4 G532L G732L系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;Windows10 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…

计算机应用数学--第一次作业

第一次作业计算题编程题 &#xff08;20分&#xff09; 第一次作业 计算题 &#xff08;20分&#xff09;求 E ( X ) E(X) E(X)&#xff0c; V a r ( X ) Var(X) Var(X) &#xff08;1&#xff09; X X X 服从 [ a , b ] [a,b] [a,b] 均匀分布。 &#xff08;2&#xff09;…

2024年智慧教育与社会科学国际会议 (ICSSS 2024)

2024年智慧教育与社会科学国际会议 (ICSSS 2024) 2024 International Conference on Smart Education and Social Sciences 【重要信息】 大会地点&#xff1a;北京 大会官网&#xff1a;http://www.icicsss.com 投稿邮箱&#xff1a;icicssssub-conf.com 【注意&#xff1a;稿…

Stable-diffusion-WebUI 的API调用(内含文生图和图生图实例)

前情提要 在之前尝试使用Diffusers库来进行stable-diffusion的接口调用以及各种插件功能实现&#xff0c;但发现diffusers库中各复杂功能的添加较为麻烦&#xff0c;而且难以实现对采样器的添加&#xff0c;safetensors格式模型的读取。在官网上找到了webui有专门的api接口&am…

1117 数字之王

solution 判断现有数字是否全为个位数 全为个位数&#xff0c;找出出现次数最多的数字&#xff0c;并首行输出最多出现次数&#xff0c;第二行输出所有出现该次数的数值不全为个位数 若当前位数值为0&#xff0c;无需处理若当前位数值非0&#xff0c;则每位立方相乘&#xff0…

10.x86游戏实战-汇编指令lea

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

Prometheus + Grafana 监控系统搭建使用指南-redis_exporter 安装与配置

Redis 接入 Prometheus 监控系统 系列文章目录 Prometheus 的安装部署Grafana的安装部署Linux服务器接入Prometheus监控-Node Exporter 安装指南Prometheus 接入SpringBoot微服务监控Mysql 接入 Prometheus RocketMQ 接入Prometheus 监控ElasticSearch 接入 PrometheusNacos …

vue使用axios获取信息的案例

List组件&#xff08;用来展示搜索的信息&#xff09; <template><div class"row"><!-- 列表数据 --><div class"card" v-for"user in info.users" :key"user.login" v-show"info.users.length">&l…

智慧校园-资产管理系统总体概述

智慧校园资产管理系统是面向教育机构设计的一体化数字平台&#xff0c;其核心目标在于通过先进的信息技术手段&#xff0c;全面优化校园内部的资产管理流程。该系统致力于提升资产管理的效率与透明度&#xff0c;同时降低成本并确保所有操作符合财务及审计规范&#xff0c;为校…

RNN文献综述

循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种专门用于处理序列数据的神经网络模型。它在自然语言处理、语音识别、时间序列预测等领域有着广泛的应用。本文将从RNN的历史发展、基本原理、应用场景以及最新研究进展等方面进行综述。 历…

TC3xx NvM小细节解读

目录 1.FlsLoader Driver和FlsDmu Driver 2. FlsLoader小细节 3.小结 大家好&#xff0c;我是快乐的肌肉&#xff0c;今天聊聊TC3xx NvM相关硬件细节以及MCAL针对NvM的驱动。 1.FlsLoader Driver和FlsDmu Driver 在最开始做标定的时候&#xff0c;认为标定数据既然是数据&…

比赛获奖的武林秘籍:02 国奖秘籍-大学生电子计算机类竞赛快速上手的流程,小白必看

比赛获奖的武林秘籍&#xff1a;02 国奖秘籍-大学生电子计算机类竞赛快速上手的流程&#xff0c;小白必看 摘要 本文主要介绍了大学生参加电子计算机类比赛&#xff08;电赛、光电设计大赛、计算机设计大赛、嵌入式芯片与系统设计大赛等比赛&#xff09;的流程和涉及到的知识…

3dmax全景图用什么渲染软件好?渲染100邀请码1a12

全景图是常见的效果图类型&#xff0c;常用于展示大型空间&#xff0c;如展厅、会议室等。全景图的制作需要渲染&#xff0c;下面我介绍几个常用的渲染软件分享给大家。 1、V-Ray&#xff1a;十分流行的渲染引擎&#xff0c;功能强大&#xff0c;它提供了高质量的光线追踪技术…

六、资产安全—信息分级资产管理与隐私保护练习题(CISSP)

六、资产安全—信息分级资产管理与隐私保护(CISSP): 六、资产安全—信息分级资产管理与隐私保护(C

RAM和ROM的区别

RAM和ROM的区别 RAM和ROM都是用来存东西的&#xff0c;比如我们熟悉的CPU缓存、电脑和手机的内存就是属于RAM&#xff0c;而固态硬盘、U盘&#xff0c;还有我们买手机时候说的32G、64G的存储空间&#xff0c;就属于ROM。RAM和ROM的区别&#xff0c;简单说就是RAM在断电之后&am…