【Linux】system V 共享内存

这篇具有很好参考价值的文章主要介绍了【Linux】system V 共享内存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

system V

system V 是一套标准,独立于文件系统之外的,专门为了通信设计出来的模块
让两个毫不相关的进程看到同一份资源

1. 共享内存原理

第一阶段原理

【Linux】system V 共享内存

进程A和进程B都通过自己的页表映射到物理内存中的特定区域,进而找到该进程匹配的代码和数据
为了让进程A和进程B通信,前提是两者要看到同一份资源
假设在物理内存上开辟一块空间
进程A和进程B在自己的地址空间中都有自己的共享区
想办法把物理内存中新开辟空间 通过页表 映射到 进程A和进程B的共享区中
把地址空间的起始地址返回给用户
进程A和进程B就可以通过起始的虚拟地址,对应页表访问到内存
就完成了让进程A和进程B看到同一份资源,这份资源就被称为共享内存

第二阶段原理

【Linux】system V 共享内存

系统中可以用ssh进行通信 ,是不是只能有一对进程使用共享内存呢?
可以,其他进程也可以通信
所以在任何时刻,可能有多个共享内存在被使用
系统中一定会存在很多共享内存同时存在
操作系统要不要整体管理所有的共享内存呢?要
操作性系统如何管理多个共享内存呢?
先描述,在组织
并不是在内存中开辟空间即可,系统为了管理共享内存,构建对应的描述共享内存的结构体对象
共享内存=共享内存的内核数据结构(伪代码:struct shm)+真正开辟的内存空间

2. 直接写代码–编写代码进行原理介绍


打开vscode,创建文件client.cc和server.cc(后缀为cc说明是c++)的文件
创建公共路径 comm.hpp

shmget函数

创建共享路径接口 ,输入 man shmget 查看
【Linux】system V 共享内存

申请一个 系统V的共享内存块
如果创建成功,则会返回共享内存标识符,失败返回-1


size代表申请内存块的大小
shmflg代表 选项
有两个最常用的选项,IPC_CREAT IPC_EXCL
转到定义就可以发现其实这两个都是宏


【Linux】system V 共享内存

若单独使用 IPC_CREAT :创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,就获取已经存在的共享内存并返回
IPC_EXCL不能单独使用 ,一般都要配合 IPC_CREAT
若要将两个选项同时传进去 IPC_CREAT | IPC_EXCL
两个选项同时用: 创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,则立马出错返回
如果创建成功,对应的共享内存一定是最新的


获取共享内存时,需要有一个key值

ftok函数

输入 man ftok

【Linux】system V 共享内存

根据路径和项目id进行算法结合,形成一个冲突概率低的key值
失败就返回-1,成功返回key值

key值用法

假设进程A创建了一个共享内存,但是进程B怎么知道那个共享内存是创建的吗?
就需要借助上述提到的 ftok 函数

【Linux】system V 共享内存

【Linux】system V 共享内存

刚开始约定好 A和B用同样的路径字符串和项目id
借助A形成一个key值,将key值放入A创建的共享内存描述结构体中
此时B也形成一个相同的key值,通过寻找key值来找到A所创建的共享内存


pathname 代表 用户自己设定的路径字符串
proj_id 代表 项目id
key值意义为
让创建共享内存的进程可以给新共享内存设置key值
让获取共享内存的进程 通过key值 去找特定匹配的共享内存

1. 创建key值

【Linux】system V 共享内存

comm.hpp 公共路径中构建一个函数 Getkey 用于返回key值


【Linux】system V 共享内存

构建一个函数 tohex,用于将数转换为十六进制


【Linux】system V 共享内存

通过server.cc与client.cc中分别调用Getkey 与tohex函数


【Linux】system V 共享内存

两者的返回值key 是相同的,并且返回的都是十六进制数

2. 创建共享内存 获取共享内存

【Linux】system V 共享内存
创建共享内存,调用shmget函数,通过两个选项 若共享内存不存在则创建,若存在则报错
而获取共享内存,调用shmget函数,则返回已有的共享内存


【Linux】system V 共享内存

此时运行可执行程序,发现server与client的shmid(共享内存标识符)相同

3. 将自己和共享内存关联起来

输入 man shmat 指令
【Linux】system V 共享内存
at代表 关联
将共享内存和目标值关联起来
返回值为 共享内存的虚拟地址的起始地址
我们不知道应该把共享内存放在虚拟空间的什么地址处,所以shmaddr设为NULL让系统自主去选择
shmflg 可以设置为 SHM_RDONLY 表示当前共享内存是只读的 一般设为0,默认为读写的


【Linux】system V 共享内存

4. 将自己和共享内存取消关联

输入 man shmdt 指令
【Linux】system V 共享内存
shmdt代表 虚拟地址
成功返回0,失败返回-1

【Linux】system V 共享内存

5. 删除共享内存

创建共享内存的进程已经早就退出了,但是共享内存还存在
确认共享内存存在: ipcs
ipc作为进程间通信的简写
ipc表示资源 s表示有多个资源

【Linux】system V 共享内存
显出来的为ipc通信系统所支持的三种ipc通信策略
Message Queues 消息队列
Shared Memory Segments 共享内存段
Semaphore Arrays 信号量


ipcs - m 查看共享内存段

【Linux】system V 共享内存
perms 代表权限
bytes 代表字节数
nattch 代表 有几个进程和当前进程是关联的

用指令删除

key是在操作系统中使用的,类似于文件的inode编号
shmid 类似于文件的fd
所以删除操作,是在用户层,应该用shmid

【Linux】system V 共享内存


ipcrm -m shmid值 就可以删除共享内存
此时就没有 shmid为0的共享内存 存在了

调用系统调用

输入 man shmctl 指令

【Linux】system V 共享内存
shmid 代表 共享内存描述符 即想对那个共享内存操作
cmd 代表 选项 即想做什么操作
IPC_STAT 获取当前共享内存的属性
IPC_SET 设置共享内存属性
IPC_RMID 标记这个段被释放
buf 代表 共享内存的属性

【Linux】system V 共享内存

在comm.hpp下 设置删除共享内存的函数,在server.cc中调用函数 即可删除共享内存

完整代码

makefile
.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^
client:client.cc
	g++ -o $@ $^
.PHONY:clean
clean:
	rm -f server client 

如何使两个可执行程序运行,在上一篇文章提到过,点击查看:命名管道文章来源地址https://www.toymoban.com/news/detail-417419.html


comm.hpp
#ifndef _COMM_HPP_
#define _COMM_HPP_
#include<iostream>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<assert.h>
using namespace std;

#define PATHNAME "."//.表示当前路径  路径字符串
#define PROJID 0x6666 //项目id
const int gsize=4096;
key_t getkey()//用于返回key值
{
    key_t k=ftok(PATHNAME,PROJID);
    if(k==-1)//失败
    {
       cout<<errno<< " :" <<strerror(errno)<<endl;
       exit(1);
    }
    return k;//返回key值
}
string tohex(int x)//转换为十六进制
{
   char buffer[64];
   //将x以十六进制的形式传给buffer
   snprintf(buffer,sizeof(buffer),"0x%x",x);
   return buffer;
}

static int  createshmhelper(key_t k,int size,int flag)//static修饰只在本文件有效
{
     
  int shmid=shmget(k,size,flag);
  if(shmid==-1)//创建失败
  {
    cout<<errno<< " :" <<strerror(errno)<<endl;
       exit(2);
  }
  return  shmid;//返回共享内存标识符
}

int createshm(key_t k,int size)//创建共享内存
{
    //带有两个选项 若不存在则创建,若存在则报错
    return createshmhelper(k,size,IPC_CREAT |IPC_EXCL);
}

int getshm(key_t k,int size)
{
    //若有共享内存,则返回已有的共享内存
     return createshmhelper(k,size,IPC_CREAT );
}

char* attachshm(int shmid)//关联
{
    char*start=(char*)shmat(shmid,NULL,0);//对应类型void* 所以需要强转
     return start;
}

void detachshm(char*start)//取消关联
{
 int n=shmdt(start);
 assert(n!=-1);
 (void)n;
}

void delshm(int shmid)
{
   int n=shmctl(shmid,IPC_RMID,NULL);
   assert(n!=-1);//为-1就删除失败
   (void)n;
}


#endif 

server.cc
#include"comm.hpp"
#include<unistd.h>
int main()
{
    //1. 创建key值
  key_t k=getkey();//获取key值
  cout<<"server:"<<tohex(k)<<endl;

   //2.创建共享内存
   int shmid=createshm(k,gsize);//返回的是共享内存标识符
   cout<<"server shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制
   sleep(5);
  

   // 3.将自己和共享内存关联起来
   char*start=attachshm(shmid);

   //通信
    
   //4. 将自己和共享内存取消关联
    detachshm(start); 
  

   //5.删除共享内存
    delshm(shmid);
    return 0;
}


client.cc
#include"comm.hpp"

int main()
{
  key_t k=getkey();//获取key值
  cout<<"client key:"<<tohex(k)<<endl;

int shmid=getshm(k,gsize);//获取共享内存
cout<<"client shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制

  char*start=attachshm(shmid);
   detachshm(start); 
  

  
    return 0;
}

到了这里,关于【Linux】system V 共享内存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】System V 共享内存、消息队列、信号量

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 System V 共享内存是一种进程间通信的机制,它允许多个进程 共享一块物理内存区域 (称为“段”)。System V 共享内存的优点是效率高,因为进程之间不需要复制数据;缺点是 需要进程之间进行同步,以避免数据的不一致性 。 共

    2024年02月04日
    浏览(50)
  • 【Linux从入门到精通】通信 | 共享内存(System V)

        本篇文章接着上篇文章通信 | 管道通信(匿名管道 命名管道)进行讲解。本篇文章的中点内容是 共享内存 。 文章目录  一、初识与创建共享内存 1、1 什么是共享内存 1、2 共享内存函数 1、2、1 创建共享内存 shmget 1、2、2 ftok 生成 key 1、2、3 获取共享内存 shmget 1、3 dem

    2024年02月09日
    浏览(43)
  • 【Linux】进程间通信——system V共享内存 | 消息队列 | 信号量

    共享内存是一种在多个进程之间进行进程间通信的机制。它允许多个进程访问相同的物理内存区域,从而实现高效的数据交换和通信。 因为 进程具有独立性(隔离性) ,内核数据结构包括对应的代码、数据与页表都是独立的。OS系统为了让进程间进行通信,必须让不同的进

    2024年02月15日
    浏览(52)
  • Linux之进程间通信——system V(共享内存、消息队列、信号量等)

    本文介绍了另一种进程间通信——system V,主要介绍了共享内存,消息队列、信号量,当然消息队列了信号量并非重点,简单了解即可。 共享内存 :不同的进程为了进行通信看到的同一个内存块,该内存块被称为共享内存。 进程具有独立性,它的内核数据结构包括对应的代

    2024年02月08日
    浏览(60)
  • 【探索Linux】—— 强大的命令行工具 P.15(进程间通信 —— system V共享内存)

    在多进程编程中,进程间通信(IPC)是一项关键技术,它使得不同的进程能够相互交换数据和协调行为。而在众多的IPC机制中,System V共享内存是一种高效且强大的通信方式。通过使用共享内存,我们可以将数据从一个进程快速地传递给另一个进程,避免了复制数据的开销,

    2024年02月05日
    浏览(62)
  • system-v IPC共享内存通信

    目录 system v IPC简介 共享内存需要用到的函数接口 shmget函数--获取对象ID shmat函数--获得映射空间 shmctl函数--释放资源 共享内存实现思路 注意 消息队列、共享内存和信号量统称为system v IPC(进程间通信机制),V是罗马数字5,是UNIX的ATT分支的其中一个版本,一般称它们为IPC对象

    2024年04月26日
    浏览(50)
  • linux(system V标准)信号量

    目录:             1.什么是信号量             2.信号量的本质 1.什么是信号量   2.信号量的本质  什么是临界资源呢?? 凡是倍多个执行流同时访问的资源就是临界资源!!! 我们看一个问题,我们fork()之后创建一个子进程,那么我们的全局变量,是不是我们父

    2024年02月07日
    浏览(43)
  • linux(system V标准)进程间通信2

    目录:              1.回顾上一节的代码              2.shmat、shmdt的使用              3.共享内存的大小为什么最好设置成4096字节的整数倍呢?              4.操作系统如何管理共享内存的 --------------------------------------------------------------------------------

    2024年02月07日
    浏览(79)
  • (26)Linux 进程通信之共享内存(共享储存空间)

    共享内存是System V版本的最后一个进程间通信方式。 共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内

    2024年01月16日
    浏览(46)
  • Linux进程通信——共享内存

    两个进程的PCB创建虚拟地址空间然后映射到物理内存中,每个进程因为是独立的,所以在物理内存中的地址也不同。 那么共享内存是怎么做到的呢? 首先先在物理内存中申请一块内存。 然后讲这块内存通过页表映射分别映射到这两个进程的虚拟地址空间内,让这两个进程都

    2024年02月01日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包