Linux_共享内存通信

news2024/10/7 10:16:24

目录

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.coloradmin.cn/o/1898343.html

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

相关文章

【C++】日期类

鼠鼠实现了一个日期类&#xff0c;用来练习印证前几篇博客介绍的内容&#xff01;&#xff01; 目录 1.日期类的定义 2.得到某年某月的天数 3.检查日期是否合法 4.&#xff08;全缺省&#xff09;构造函数 5.拷贝构造函数 6.析构函数 7.赋值运算符重载 8.>运算符重…

【论文阅读】VASA-1: Lifelike Audio-Driven Talking FacesGenerated in Real Time

整体框架。不直接生成视频帧&#xff0c;而是在潜在空间中生成整体面部动态和头部运动&#xff0c;条件是音频和其他信号。给定这些运动潜在编码&#xff0c;通过面部解码器生成视频帧&#xff0c;还接受从输入图像中提取的外观和身份特征作为输入。 构建了一个面部潜在空间并…

JMH320【亲测】【御剑九歌】唯美仙侠手游御剑九歌+WIN学习手工端+视频教程+开服清档+运营后台+授权GM物品充值后台

资源介绍&#xff1a; 这也是仙梦奇缘的一个游戏 注意&#xff1a;外网14位IP或域名 ———————————————————————————————————– ps后台介绍: 1区运营后台&#xff1a;http://ip:9981/admin/admintool/ 2区运营后台&#xff1a;http://ip…

Finding Global Homophily in Graph Neural Networks When Meeting Heterophily

本文发表于:ICML22 推荐指数: #paper/⭐⭐⭐ 问题背景: 异配图的邻接矩阵难以确定,以及异配图的计算复杂度开销大 可行的解决办法:高通滤波多跳邻居,GPRGNN(pagerank一类&#xff0c;各阶邻居的权重不同,ACM-GCN&#xff08;高低通滤波,H2GCN&#xff08;应该复杂度很大&…

阶段总结——基于深度学习的三叶青图像识别

阶段总结——基于深度学习的三叶青图像识别 文章目录 一、计算机视觉图像分类系统设计二、训练模型2.1. 构建数据集2.2. 网络模型选择2.3. 图像数据增强与调参2.4. 部署模型到web端2.5. 开发图像识别小程序 三、实验结果3.1. 模型训练3.2. 模型部署 四、讨论五、参考文献&#…

Rocky Linux 9.4基于官方源码制作openssh 9.8p1二进制rpm包 —— 筑梦之路

2024年7月1日&#xff0c;openssh 9.8版本发布&#xff0c;主要修复了CVE-2024-6387安全漏洞。 由于centos 7的生命周期在6月30日终止&#xff0c;因此需要逐步替换到Rocky Linux&#xff0c;后续会有更多分享关于Rocky Linux的文章。 环境说明 1. 操作系统版本 cat /etc/o…

GuLi商城-商品服务-API-品牌管理-效果优化与快速显示开关

<template><div class"mod-config"><el-form :inline"true" :model"dataForm" keyup.enter.native"getDataList()"><el-form-item><el-input v-model"dataForm.key" placeholder"参数名&qu…

ASUS/华硕枪神5 G533Q G733Q系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

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

(仿真+报告+源码)基于51单片机的温湿度监测系统

&#xff08;仿真报告源码&#xff09;基于51单片机的温湿度监测系统 付费后获得百度网盘链接&#xff0c;网盘链接在最后&#xff0c;有问题私信哦~~~ 一.系统简介 该系统由单片机、温湿度传感器器、液晶显示器以及浇水控制电路组成。该系统使用AT89C51单片机作为控制核心&…

JavaScript(6)——数据类型转换

为什么需要类型转换&#xff1f; JavaScript是弱数据类型&#xff1a;JavaScript不知道变量到底属于哪种数据类型&#xff0c;只有赋值了才清除 使用表单&#xff0c;prompt获取的数据默认为字符串类型&#xff0c;此时不能直接进行算数运算 隐式转换 某些运算符被执行时&am…

常规情况与opencv图像中,计算直线与矩形框的交点

文章目录 1、普通方式1.1、普通计算过程1.2、优化方式 2、图像中的情况2.1、常规处理2.2、opencv中的处理2.2.1、cv::clipLine函数2.2.2、测试代码2.2.3、测试结果 1、普通方式 已知矩形框左上(x1,y1)、右下(x2,y2&#xff09;点&#xff0c;直线方程 y kxb&#xff0c;求交点…

Ubuntu / Debian安装FTP服务

本章教程,记录在Ubuntu中安装FTP服务的具体步骤。FTP默认端口:21 1、安装 pure-ftpd sudo apt-get install pure-ftpd2、修改默认配置 # 与 centos 不同,这里需要在 /etc/pure-ftpd/conf 文件夹下执行下列命令,增加对应配置文件: # 创建 /etc/pure-ftpd/conf/PureDB 文件…

4.2 投影

一、投影和投影矩阵 我们以下面两个问题开始&#xff0c;问题一是为了展示投影是很容易视觉化的&#xff0c;问题二是关于 “投影矩阵”&#xff08;projection matrices&#xff09;—— 对称矩阵且 P 2 P P^2P P2P。 b \boldsymbol b b 的投影是 P b P\boldsymbol b Pb。…

金属3D打印如何精准选材

随着3D打印技术的飞跃发展&#xff0c;模具制造领域迎来了前所未有的创新机遇。在众多3D打印技术中&#xff0c;SLM金属3D打印以其精度高、复杂结构成型能力&#xff0c;成为众多行业的优选。然而&#xff0c;金属打印材料&#xff0c;如何精准选择&#xff0c;以最大化满足项目…

ASP.NET MVC-razor编写-2-svg中使用js+添加事件监听

环境&#xff1a;win10 效果 初始状态&#xff1a; 鼠标移入某个text&#xff08;比如KS primer&#xff09;时&#xff0c;text和连接的线条与箭头都变色&#xff1a; 鼠标移出时回复正常。 如果是移入另一种红色的text&#xff08;比如Cell Sceening Tag&#xff09;&…

Python学习笔记29:进阶篇(十八)常见标准库使用之质量控制中的数据清洗

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…

【数据结构】(6.2)堆的应用——Top-K问题(C语言)

系列文章目录 文章目录 系列文章目录问题引入一、TopK 问题 是什么&#xff1f;二、TopK 问题解决思路2.1 TopK 思路2.2 随机产生数字2.2 完整代码2.3 验证结果 问题引入 TopK 问题 (在一堆数据里面找到前 K 个最大 / 最小的数)。 一、TopK 问题 是什么&#xff1f; 生活中也…

太速科技-FMC209-基于FMC的4路125MAD输入、2路1GDA输出子卡

FMC209-基于FMC的4路125MAD输入、2路1GDA输出子卡 一、板卡概述 本子卡基于FMC连接器实现4路125M采样率AD输出&#xff0c;两路1G采样率DA输出子卡&#xff0c;板卡默认由FMC连接器12V供电&#xff0c;支持外参考时钟&#xff0c;外输入时钟&#xff0c;外触发。 …

全端面试题15(canvas)

在前端开发领域&#xff0c;<canvas> 元素和相关的 API 是面试中经常被提及的主题。下面是一些常见的关于 HTML5 Canvas 的面试问题及解答示例&#xff1a; 1. 什么是 <canvas> 元素&#xff1f; <canvas> 是 HTML5 引入的一个用于图形渲染的标签。它本身并…

使用ChatGPT写论文,只需四步突破论文写作瓶颈!

欢迎关注&#xff0c;为大家带来最酷最有效的智能AI学术科研写作攻略。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥&#xff08;yida985&#xff09;交流 地表最强大的高级学术AI专业版已经开放&#xff0c;拥有全球领先的GPT学术科研应用&#xff0c;有兴趣的朋友可…