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

Linux笔记---System V共享内存

1. System V共享内存简介

System V共享内存是一种在Linux系统中用于进程间通信的机制。顾名思义,就是申请一段可供多个进程共享的内存,以用于进程间通信,相对于管道机制要更加直接。

1.1 原理

System V共享内存通过创建和使用一个特定的IPC键来标识共享内存段,允许进程通过调用shmget创建一个新的共享内存段或访问一个已存在的共享内存段,然后使用shmat和shmdt来挂载和卸载内存。

1.2 特点

  • 高效快速:共享内存是进程间通信的一种最基本、最快速的机制,一旦共享内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,进程不再通过执行进入内核来传递彼此的数据,从而提高了数据传输的效率。

  • 底层控制:提供了更底层的控制方式,适合需要对内存进行精细管理和控制的场景。

  • 广泛支持:在较早的UNIX版本中引入,在各种UNIX-like系统中都有广泛支持。

1.3 使用步骤

要使一个进程获得一段指定的共享内存并正确使用,需要按照以下步骤进行操作:

  1. 获取共享内存段:使用shmget函数获取或创建(如果共享内存不存在)共享内存段。
  2. 挂载共享内存段:使用shmat函数将获取到的共享内存段映射到进程地址空间。
  3. 使用共享内存段:像使用malloc申请的内存一样使用共享内存(注意不要越界),期间可通过shmctl函数对共享内存段进行控制。
  4. 卸载共享内存段:使用shmdt函数解除共享内存段到进程地址空间的映射。
  5. 释放共享内存段:共享内存段不再使用时(所有进程都卸载了这个共享内存段),使用shmctl函数将共享内存段释放。

注意:共享内存未提供同步机制,在使用时通常需要借助信号量等其他机制来同步对共享内存的访问。 

2. 使用方法


2.1 获取共享内存段(shmget)

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);

功能:获取一段共享内存(获取到这段共享内存的描述符)。 

函数参数

  • key:用于标识共享内存的键值,该键值由使用共享内存的双方进行规定,以确保二者获取到的是同一块共享内存。

  • size:要创建共享内存的大小,所有的内存分配操作都是以页为单位的,所以即使只申请只有一个字节的内存,内存也会分配整整一页。

  • shmflg:表示创建的共享内存的模式标志参数,常用的有以下两个:

    • IPC_CREAT:如果内核中不存在关键字与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符。

    • IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错。

    • 通常负责创建共享内存的进程使用参数(IPC_CREAT | IPC_EXCL),而使用共享内存的进程使用参数(IPC_EXCL)。

返回值

  • 成功:返回共享内存的标识符(类似于文件描述符)。

  • 出错:-1,错误原因存于errno中。

 键值的常用获取方式

键值发生冲突是很有可能的,所以我们要尽可能地采用不易发生冲突的方式来产生键值,最常用的一个方法就是使用ftok函数来生成。

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);

通常我们传入当前项目所在路径作为第一个参数,传入一个随机值(或特定值)作为第二个参数。

ftok的返回值就是根据传入参数生成的一个键值。


2.2 挂载/卸载共享内存段(shmat/shmdt)

#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);

功能:将共享内存段连接到进程的地址空间,使得进程能够访问共享内存中的数据。 

函数参数

  • shmid:由shmget函数返回的共享内存标识符,用于标识要连接的共享内存段。

  • shmaddr:指定共享内存连接到进程中的地址位置,通常设置为0,表示由系统自动选择合适的虚拟内存地址。

  • shmflg:一组标志位,通常为0。如果设置了SHM_RDONLY位,则以只读方式连接共享内存段;否则以读写方式连接。

返回值

  • 成功:返回一个指向共享内存第一个字节的指针,进程可以通过该指针访问共享内存中的数据。

  • 失败:返回-1。


#include <sys/types.h>
#include <sys/shm.h>int shmdt(const void *shmaddr);

功能:将共享内存从进程的地址空间中分离,使进程无法再访问该共享内存段,但并不删除共享内存本身。

函数参数shmaddr是shmat函数返回的地址指针,即指向要分离的共享内存段的指针。

返回值

  • 成功:返回0。

  • 失败:返回-1。


 2.3 释放共享内存(shmctl)

不同于之前的函数,释放共享内存只是shmctl的功能之一。

#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数说明

  • shmid:共享内存段的标识符,通常是由shmget函数返回的。

  • cmd:要执行的操作命令,删除指定共享内存段:IPC_RMID

  • buf:一个指向struct shmid_ds类型结构的指针,该结构包含共享内存段的状态信息。根据cmd参数的不同,buf参数可以用于输入或输出。

返回值

  • 成功时,shmctl函数返回0。

  • 失败时,返回-1,并设置相应的errno。

 加入在我们的程序结束时不及时删除共享内存段的话,这个共享内存段就会一直存在于系统当中,直到我们主动进行删除。

共享内存既然是各个进程都可以看到的资源,那么在系统当中必然也是要对其进行单独的描述的,由于Linux下一切皆文件,所以在系统当中必然会存在一个描述共享内存的文件。

我们可以通过ipcs -m命令查看系统当中存在的共享内存:

若在程序当中没有及时删除,想要主动删除某个共享内存的话,可以使用ipcrm -m <shmid>来删除指定共享内存:

 3. 使用示例

用一个客户端和服务器进行通讯的例子来展示共享内存的用法。

客户端依次向共享内存当中写入26个大写英文字母(每种两个),每当客户端完成一次写入,服务器端就将共享内存中的数据打印一次。

由于共享内存本身不存在同步机制,所以下面的代码利用了命名管道所拥有的同步机制来实现客户服务器之间的同步。

大筒木老辈子/Linux_C++ - Gitee.com

相关文章:

  • 海市蜃楼的形成原理
  • JVM之内存管理(二)
  • vue 组件函数式调用实战:以身份验证弹窗为例
  • 数字相机的快门结构
  • 互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现-3
  • 4.6java异常处理
  • 每日算法刷题Day2 5.10:leetcode数组1道题3种解法,用时40min
  • Java零组件实现配置热更新
  • C++发起Https连接请求
  • PyQt5基础:QWidget类的全面解析与应用实践
  • 利用多AI协作实现AI编辑器高效开发:创新架构与实践基本构想
  • 【typenum】 1 说明文件(README.md)
  • 【金仓数据库征文】政府项目数据库迁移:从MySQL 5.7到KingbaseES的蜕变之路
  • 数据库故障排查指南大纲
  • Tailwind CSS v4 主题化实践入门(自定义 Theme + 主题模式切换)✨
  • 边缘计算从专家到小白
  • MySQL开篇
  • vscode 中 tasks.json schema
  • 前端面试每日三题 - Day 30
  • AtCoder Beginner Contest 405(CD)
  • 2025上海十大动漫IP评选活动启动
  • 湖北宜昌:在青山绿水间解锁乡村振兴“密码”
  • 《中国人民银行业务领域数据安全管理办法》发布,6月30日起施行
  • 中国驻美国大使馆发言人就中美经贸高层会谈答记者问
  • 万里云端遇见上博--搭乘“上博号”主题飞机体验记
  • 巴基斯坦所有主要城市宣布进入紧急状态,学校和教育机构停课