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

共享内存的理解

 

目录

直接原理

原理图​编辑

直接代码

创建唯一键值代码 

创建共享内存代码 

共享内存的指令操作 

 简单封装

补充指令集



系统设计的只能本地进行通信;

直接原理

共享内存也是进程间通信的方案

原理图

理解:

1.   所有图中所说的操作都是os所做的 

2.   os必须提供1和2步骤的系统调用,供进程A和B进行调用

3.   共享内存在os中可以同时存在多份(因为不止A和B进程,可能还有E和F,G和J等),供不同对进程同时进行通信

4.   os注定了要对共享内存进行管理!------先描述后组织--------决定了共享内存不是简单的一段内存空间,也要有描述并管理共享内存的数据结构和匹配的算法!

5.   共享内存=内存空间(数据)+共享内存的操作

直接代码





这个shmget完成的是1步骤,并且是系统调用;
ftok 是一个用于生成唯一的系统V IPC (Inter-Process Communication) 标识符的函数,用于根据文件路径和一个项目标识符生成一个唯一的键值;pathname: 指向一个文件路径的字符串。ftok 将使用这个文件的 inode 信息来生成键值;proj_id: 一个项目标识符,通常是一个字符,用于在同一文件路径下区分不同的键值,通常是单字符的整数,范围从 0 到 255;

创建唯一键值代码 

shm.hpp

//shm是共享内存的缩写
#ifndef __SHM_HPP__ 
//检查 __SHM_HPP__ 这个宏是否未定义。如果未定义,则执行接下来的代码,直到遇到 #endif。
#define __SHM_HPP__ 
//定义 __SHM_HPP__ 宏。这样,如果这个头文件再次被包含,#ifndef 检查将失败,文件内容不会被再次处理,从而避免了重复定义的问题。#include<iostream>
#include<string>
#include <sys/ipc.h>
#include <sys/shm.h>const std::string pathname="/root/pipe/4.shm";//绝对路径
const int proj_id=0x66;//项目标识符key_t getcommkey(const std::string & pathname, int proj_id){key_t k=ftok(pathname.c_str(),proj_id); //生成键值if(k<0){perror("ftok");}return k;
}#endif 
//结束 #ifndef 的条件编译指令。

client.cc

#include"shm.hpp"
int main(){key_t key=getcommkey(pathname,proj_id);std::cout<<"key: "<<key<<std::endl;return 0;
}

serve.cc 

#include"shm.hpp"
int main(){key_t key=getcommkey(pathname,proj_id);std::cout<<"key: "<<key<<std::endl;return 0;
}

创建共享内存代码 

shm.hpp

//shm是共享内存的缩写
#ifndef __SHM_HPP__ 
//检查 __SHM_HPP__ 这个宏是否未定义。如果未定义,则执行接下来的代码,直到遇到 #endif。
#define __SHM_HPP__ 
//定义 __SHM_HPP__ 宏。这样,如果这个头文件再次被包含,#ifndef 检查将失败,文件内容不会被再次处理,从而避免了重复定义的问题。#include<iostream>
#include<string>
#include <sys/ipc.h>
#include <sys/shm.h>const std::string pathname="/root/pipe/4.shm";//绝对路径
const int proj_id=0x66;//项目标识符key_t getcommkey(const std::string & pathname, int proj_id){//创建唯一键值key_t k=ftok(pathname.c_str(),proj_id); //生成键值if(k<0){//失败perror("ftok");}return k;
}int shmgget(key_t key,int size){//创建共享内存int shmid=shmget(key,size,IPC_CREAT | IPC_EXCL);//返回值是共享内存的标识符if(shmid<0){//失败perror("shmget");}return shmid;
}#endif 
//结束 #ifndef 的条件编译指令。

silent.cc

#include"shm.hpp"
int main(){key_t key=getcommkey(pathname,proj_id);std::cout<<"key: "<<key<<std::endl;int shmid=shmgget(key,4096);std::cout<<"shmid: "<<shmid<<std::endl;return 0;
}


为什么第二次就失败了呢?

因为文件已存在,因为我创建时用的是IPC_CREAT | IPC_EXCL(不存在就创建,存在就出错返回)第二次调用原本就有了所以第二次出错返回;

而且共享内存不随着进程的释放而释放,所以就第二次报错;他会一直存在直到系统重启,所以需要手动释放(指令或者其他系统调用)。

他的生命周期随内核,文件的生命周期随进程;

共享内存的指令操作 

 ipcs -m 命令用于显示系统中的共享内存段信息。它会列出所有当前存在的共享内存段的详细信息,比如标识符、大小、创建时间等。这个命令有助于你了解系统内存的使用情况。

删除的话只能用shmid删除:   ipcrm -m 是一个用于删除共享内存段的命令



可以理解为key是内核用的,shmid是用户用的;

注意:
在删除共享内存段之前,请确保没有任何进程正在使用它。
删除共享内存段会释放该内存区域,并且该共享内存段中的数据将会丢失。

 删除之后再运行就能跑,细节是shmid变化了,key没变

 简单封装

shm.hpp

// shm是共享内存的缩写
#ifndef __SHM_HPP__
// 检查 __SHM_HPP__ 这个宏是否未定义。如果未定义,则执行接下来的代码,直到遇到 #endif。
#define __SHM_HPP__
// 定义 __SHM_HPP__ 宏。这样,如果这个头文件再次被包含,#ifndef 检查将失败,文件内容不会被再次处理,从而避免了重复定义的问题。#include <iostream>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>const int creater = 1;
const int user = 2;
const std::string gpathname = "/root/pipe/4.shm"; // 绝对路径
const int gproj_id = 0x66;                        // 项目标识符class shm
{
private: // 不用暴露给用户key_t getcommkey(){                                                // 创建唯一键值key_t k = ftok(_pathname.c_str(), _proj_id); // 生成键值if (k < 0){ // 失败perror("ftok");}return k;}int getcomm(key_t key, int size, int flag) // 创建共享内存的共同方法{int shmid = shmget(key, size, flag); // 返回值是共享内存的标识符if (shmid < 0){ // 失败perror("shmget");}return shmid;}public:shm(const std::string &pathname, int proj_id, int who) // 顺便告诉是谁: _pathname(pathname), _proj_id(proj_id), _who(who){_key = getcommkey(); // 键值初始化if (_who == creater)getshmforcreat();else if (_who == user)getshmforuse();std::cout << "key: " << tohex(_key) << std::endl; // 16进制打印std::cout << "shmid: " << _shmid << std::endl;}~shm(){if (_who == creater){                                                // 只有创建者才能删除int res = shmctl(_shmid, IPC_RMID, nullptr); // 进行删除操作通过调用系统接口}std::cout << "shm remove done " << std::endl;}std::string tohex(key_t key){ // 转化成16进制char buffer[128];snprintf(buffer, sizeof(buffer), "0x%x", key);return buffer;}bool getshmforcreat(){ // 创建者if (_who == creater){_shmid = getcomm(_key, 4096, IPC_CREAT | IPC_EXCL); // 调用if (_shmid >= 0){std::cout << "shm create done " << std::endl;return true; // 成功}}return false;}bool getshmforuse(){ // 使用者if (_who == user){_shmid = getcomm(_key, 4096, IPC_CREAT); // user的话只用IPC_CREAT即可if (_shmid >= 0){std::cout << "shm get done " << std::endl;return true; // 成功}}return false;}private:key_t _key;int _shmid;int _proj_id;std::string _pathname;int _who;
};#endif
// 结束 #ifndef 的条件编译指令。

serve.cc

#include"shm.hpp"int main(){shm sshm(gpathname,gproj_id,creater);return 0;
}

client.cc 

#include"shm.hpp"int main(){shm sshm(gpathname,gproj_id,user);return 0;
}



我先执行serve后执行client,导致执行client时又创建了shm,因为user是IPC_CREAT,而且打印的"shm remove done "没有删除因为他不是creater;

而serve运行后会创建又删除;

如果太快的话可以用sleep()在创建的语句停顿一下;

 shmctl 是一个用于控制共享内存段的系统调用。

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:共享内存段的标识符。
cmd:操作命令,决定要执行的具体操作。
buf:指向 shmid_ds 结构的指针,用于存储共享内存段的信息或设置参数。
常用命令 (cmd):
IPC_STAT:获取共享内存段的状态。
IPC_SET:设置共享内存段的属性。
IPC_RMID:删除共享内存段。

补充对共享内存理论的理解

共享内存的接口

补充指令集

IPC的指令


http://www.mrgr.cn/news/28059.html

相关文章:

  • 开源三代示波器的高速波形刷新方案开源,支持VNC远程桌面,手机,Pad,电脑均可访问(2024-11-11)
  • 『VUE』27. 透传属性与inheritAttrs(详细图文注释)
  • ElasticSearch-全文检索(一)基本介绍
  • 达梦数据库迁移j脚本
  • Mac解压包安装MongoDB8并设置launchd自启动
  • Redisson的可重入锁
  • GDB调试
  • 【JAVA】
  • Linux驱动编程 - platform平台设备驱动总线
  • Linux:vim编辑技巧
  • 优思学院|质量工程师在APQP中具体做哪些工作?
  • Linux基础开发环境(git的使用)
  • PCIe进阶之TL:Completion Rules TLP Prefix Rules
  • 【计算机毕设-大数据方向】基于Hadoop的在线教育平台数据分析可视化系统的设计与实现
  • 微服务实战系列之玩转Docker(十五)
  • 代码随想录训练营第34天|dp前置转移
  • Unity多国语言支持
  • 改进RRT*的路径规划算法
  • 让水凝胶不再怕溶胀:一步浸泡,拥有抗溶胀 “盔甲”
  • 【第12章】SpringBoot之SpringBootActuator服务监控(上)
  • 克隆虚拟机,xshell无法传文件,windows无法ping克隆虚拟机,已解决
  • Pandas缺失值处理
  • Dina靶机详解
  • JDBC注册驱动及获取连接
  • 【字幕】恋上数据结构与算法之015动态数组03简单接口的实现
  • TikTok商家如何通过真人测评提高流量和销量?