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

Linux下共享内存详解

共享内存是Linux中一种高效的进程间通信(IPC)方式,它允许多个进程共享同一段内存,从而实现数据的快速传递。共享内存通常比其他IPC机制(如管道或消息队列)更快,因为数据直接存储在内存中,而不需要额外的内核拷贝。

1. 共享内存的基础概念

在Linux中,共享内存有两种主要实现方式:

  • POSIX共享内存:符合POSIX标准,通过shm_openmmap等函数操作。
  • System V共享内存:这是传统的共享内存机制,依赖shmgetshmat等函数。

两者的使用场景各有不同,POSIX共享内存通常更现代化、易用,且与文件系统相关联,而System V共享内存则具有较长的历史,并且更加底层。

2. System V 共享内存

2.1 shmget 函数

shmget用于创建或获取共享内存段,语法如下:

int shmget(key_t key, size_t size, int shmflg);

  • key:共享内存段的标识符,可以通过ftok函数生成。
  • size:共享内存的大小。
  • shmflg:权限标志,通常包括读写权限(如0666)以及IPC_CREAT(创建标志)等。

示例:

key_t key = ftok("file", 65); // 生成key

int shmid = shmget(key, 1024, 0666|IPC_CREAT); // 创建1KB大小的共享内存段

2.2 shmat 函数

shmat用于将共享内存段连接到当前进程的地址空间,语法如下:

void* shmat(int shmid, const void* shmaddr, int shmflg);

  • shmid:通过shmget获取的共享内存标识符。
  • shmaddr:通常为NULL,让系统自动选择合适的地址。
  • shmflg:标志位,常用0SHM_RDONLY(只读模式)。

示例:

char* str = (char*) shmat(shmid, NULL, 0); // 连接共享内存段

2.3 shmdt 函数

shmdt用于分离共享内存段,即将共享内存从当前进程的地址空间中移除:

int shmdt(const void *shmaddr);

  • shmaddr:通过shmat返回的共享内存地址。

示例:

shmdt(str); // 分离共享内存段

2.4 shmctl 函数

shmctl用于控制共享内存段,比如删除共享内存段或获取共享内存段的信息:

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  • shmid:共享内存段的标识符。
  • cmd:控制命令,如IPC_RMID(删除共享内存段)。
  • buf:用于存储共享内存段的相关信息。

示例:

shmctl(shmid, IPC_RMID, NULL); // 删除共享内存段

3. POSIX 共享内存

3.1 shm_open 函数

shm_open用于创建或打开一个共享内存对象,它与文件相关联,并且可以通过文件描述符访问,语法如下:

int shm_open(const char *name, int oflag, mode_t mode);

  • name:共享内存对象的名称,以/开头。
  • oflag:标志位,常用O_CREAT(创建)、O_RDWR(读写)等。
  • mode:权限,如0666

示例:

int fd = shm_open("/myshm", O_CREAT | O_RDWR, 0666); // 创建/打开共享内存

3.2 ftruncate 函数

ftruncate用于调整共享内存对象的大小:

int ftruncate(int fd, off_t length);

  • fd:通过shm_open返回的文件描述符。
  • length:共享内存对象的大小。

示例:

ftruncate(fd, 1024); // 调整共享内存大小为1KB

3.3 mmap 函数

mmap用于将共享内存映射到进程的地址空间中:

void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);

  • addr:通常为NULL,表示由系统选择地址。
  • length:映射的大小。
  • prot:内存保护位,如PROT_READ(可读)、PROT_WRITE(可写)。
  • flags:标志位,如MAP_SHARED(共享)。
  • fd:通过shm_open返回的文件描述符。
  • offset:通常为0

示例:

void* ptr = mmap(0, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//映射共享内存

3.4 munmap 函数

munmap用于解除共享内存的映射:

int munmap(void* addr, size_t length);

  • addr:映射内存的地址。
  • length:映射的大小。

示例:

munmap(ptr, 1024); // 解除映射

3.5 shm_unlink 函数

shm_unlink用于删除共享内存对象,类似于System V中的shmctlIPC_RMID命令:

int shm_unlink(const char *name);

  • name:共享内存对象的名称。

示例:

shm_unlink("/myshm"); // 删除共享内存对象

4. 共享内存的同步

共享内存本质上是多个进程之间的共享区域,因此需要同步机制以防止数据竞争。常见的同步方式包括信号量(semaphore)和互斥锁(mutex)。

示例: 可以使用POSIX信号量来同步共享内存的访问:

sem_t* sem = sem_open("/mysem", O_CREAT, 0666, 1);  // 创建信号量
sem_wait(sem);  // 进入临界区
// 访问共享内存
sem_post(sem);  // 离开临界区
sem_close(sem);  // 关闭信号量
sem_unlink("/mysem");  // 删除信号量

5. 总结

共享内存是Linux进程间通信中非常重要且高效的方式,既有POSIX标准的实现,也有传统的System V接口。通过共享内存,多个进程可以在不进行大量内核拷贝的情况下快速共享数据。不过,使用共享内存时需要注意进程间的同步,以避免数据不一致或竞争条件的发生。

http://www.lryc.cn/news/444675.html

相关文章:

  • MySQL篇(管理工具)
  • redis学习笔记(六)
  • spring与springmvc整合
  • 如何使用Optuna在PyTorch中进行超参数优化
  • 2.Spring-容器-注入
  • 在uboot中添加自定义命令
  • AngularJS 模块
  • [yotroy.cool] MGT 388 - Finance for Engineers - notes 笔记
  • 2024年9月python二级易错题和难题大全(附详细解析)(三)
  • 【LLM多模态】Animatediff文生视频大模型
  • PDB数据库中蛋白质结构文件数据格式
  • C++自动驾驶面试核心问题整理
  • 2024寻找那些能精准修改PDF内容的工具
  • POI操作EXCEL增加下拉框
  • 新手教学系列——基于统一页面的管理后台设计(二)集成篇
  • 计算机毕业设计之:基于微信小程序的疫苗预约系统的设计与实现(源码+文档+讲解)
  • Redis事务总结
  • 1.4 MySql配置文件
  • 前后端分离集成CAS单点登录
  • 全栈开发(四):使用springBoot3+mybatis-plus+mysql开发restful的增删改查接口
  • 计算机组成原理==初识二进制运算
  • 【machine learning-十-grading descent梯度下降实现】
  • python网络游戏
  • 使用Charles抓包Android App数据
  • 通信工程学习:什么是VM虚拟机
  • C#环境搭建和入门教程--vs2022之下
  • 自定义类型
  • 数仓项目环境搭建
  • Vue3(二)计算属性Computed,监视属性watch,watchEffect,标签的ref属性,propos属性,生命周期,自定义hook
  • 栈:只允许在一端进行插入或删除操作的线性表