【Linux】进程间通信——共享内存

server/2025/3/26 1:37:14/

在这里插入图片描述

文章目录

  • 共享内存(Shared Memory)
    • 什么是共享内存
    • 2. 共享内存的特点
    • 3.共享内存的主要函数
      • 3.1.shmget()
      • 3.2.shmat
      • 3.3.shmdt
      • 3.4.shmctl
  • 共享内存实现进程间通信
    • ShareMemory.hpp
    • Server.cc
    • Client.cc
  • 总结

共享内存(Shared Memory)

什么是共享内存

共享内存(Shared Memory)是一种 进程间通信(IPC) 机制,允许多个进程共享同一块物理内存,从而提高数据交换效率。相比其他 IPC 方式(如管道、消息队列等),共享内存具有 速度快、低开销 的优势,因为数据直接存储在内存中,而无需通过内核进行数据拷贝。

2. 共享内存的特点

  • 高效:数据直接在内存中共享,避免了进程间数据拷贝的开销。
  • 进程可见:多个进程可以同时访问同一块共享内存,实现高速数据传输。
  • 需要同步机制:由于多个进程可以并发访问共享内存,通常需要使用 信号量(Semaphore)互斥锁(Mutex) 来防止数据竞争。

3.共享内存的主要函数

函数作用
shmget()创建或获取一个共享内存段
shmat()将共享内存附加到进程地址空间
shmdt()解除共享内存与进程的关联
shmctl()控制共享内存(删除、修改权限等)

3.1.shmget()

在这里插入图片描述
shmget表示获取共享内存,第一个参数key表示共享内存的键值,用于标识唯一的共享内存段。


这个参数由用户个人设置,但是通常用ftok函数来获取key。
在这里插入图片描述
ftok函数通过一定的算法来获取相对不会重复的key值,第一个参数是路径,第二个参数随机填一个数,通过算法获取相对唯一的key值。


shmget的第二个参数表示共享内存的大小,第三个参数表示标志位,如何创建共享内存和设置共享内存的权限。
在这里插入图片描述
第三个参数有特定的宏可以选择,红框框起来的是常用的两个。
IPC_CREAT:单独使用表示获取共享内存,如果存在则报错
IPC_CREAT | IPC_EXCL:表示创建共享内存
IPC_EXCL:单独使用没有意义

3.2.shmat

当我们获取到共享内存的时候,我们需要将共享内存挂接到虚拟内存地址当中,这时就需要用到这个接口。
在这里插入图片描述

用下面简图表示挂接:
在这里插入图片描述
shmget的第一个参数shmid表示shmget的返回值,会返回一个shmid,第二个参数表示我们可以指定一个虚拟地址,挂接到指定的虚拟地址上,但是一般情况下我们都会默认使用分配的虚拟地址,所以第二个参数一般情况下都会填nullptr,第三个参数表示标志位,用于控制映射方式(常用 0 或 SHM_RDONLY)。

3.3.shmdt

去关联,和上一个关联恰好相反,一个是关联一个是去关联。
在这里插入图片描述

3.4.shmctl

这个函数是用于控制共享内存的,在命令行我们一般用ipcrm -m shmid这个命令来删除共享内存,但是在代码层面,我们一般用shmctl这个函数来控制共享内存,可以进行删除修改权限等操作。
在这里插入图片描述

第二个参数表示标志位进行什么操作,下面是可以进行的操作,红框框起来的,表示删除共享内存,我们可以用这个宏来实现删除共享内存。
在这里插入图片描述
第三个参数是获取共享内存的信息,放在一个结构体当中,如果我们不需要获取直接传nullptr
在这里插入图片描述
接口讲完了,接下来用共享内存实现进程间通信

共享内存实现进程间通信

ShareMemory.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
const string gpath = "/home/llllyrics/112_class";
int gprojid = 0X6666;
//操作系统,申请空间,是按照块为单位的:4kb,1kb,2kb,4mb.......
int gshmsize = 4096;
mode_t gmode = 0600;//权限const int CREATE = IPC_CREAT | IPC_EXCL | gmode;
const int GET = IPC_CREAT;class ShareMemory
{
private:
void CreateShmHelper(int flag){//创建key_key = ftok(gpath.c_str(),gprojid);if(_key < 0)//创建失败{cerr<<"ftok error"<<endl;return;}//让server创建共享内存&&获取//注意:共享内存也有权限!在应用层和文件关联度不大,但是在底层和文件关联度大_shmid = shmget(_key,gshmsize,flag);//创建if(_shmid < 0)//创建失败{cerr<<"shmget error"<<endl;return;}}
public:ShareMemory():_shmid(-1),_key(0),_addr(nullptr){}~ShareMemory(){}void CreateShm(){if(_shmid == -1)CreateShmHelper(CREATE);}void GetShm(){CreateShmHelper(GET);}void AttachShm(){//将共享内存挂接到自己的地址空间当中_addr = shmat(_shmid,nullptr,0);//将共享内存挂接到自己的虚拟地址上。if((long long)_addr == -1)return;//挂接失败返回nullptr}void DetachShm(){if(_addr != nullptr)shmdt(_addr);cout<<"detach done:"<<endl;}void DeleteShm(){int n = shmctl(_shmid,IPC_RMID,nullptr);if(n < 0) {cout<<"delete failed"<<endl;return;}cout<<"delete shm done"<<endl;}void* GetAddr(){return _addr;}void ShmMeta(){}
private:int _shmid;key_t _key;void *_addr;
};
ShareMemory shm;

Server.cc

#include "ShareMemory.hpp"
int main()
{shm.CreateShm();shm.AttachShm();//接收----IPCchar* strinfo = (char*)shm.GetAddr();//获取服务器的虚拟地址while(true){sleep(1);//打印共享地址中的内容printf("%s\n",strinfo);//}shm.DetachShm();shm.DeleteShm();return 0;
}

Client.cc

#include "ShareMemory.hpp"
int main()
{shm.GetShm();shm.AttachShm();//写入----IPCchar* strinfo = (char*)shm.GetAddr();//获取客户端的虚拟地址char ch = 'A';while(ch <= 'Z'){sleep(1);strinfo[ch-'A'] = ch;//这里操作共享内存的时候为什么没有用系统调用?ch++;}shm.DetachShm();return 0;
}

总结

共享内存作为一种高效的进程间通信机制,因其直接在内存中操作数据,避免了数据拷贝,提供了快速的数据传输方式。通过 shmgetshmatshmctl 等函数,Linux 系统为我们提供了灵活的共享内存操作接口。尽管共享内存具有显著的性能优势,但由于其没有内建的同步机制,使用时必须特别注意数据的一致性和进程间的同步问题。

在实际应用中,结合信号量、消息队列等同步机制,共享内存可以为多进程间提供高效且稳定的通信手段。然而,开发者需要注意资源的管理与清理,以免造成内存泄漏或数据冲突。

总之,共享内存是一种非常强大的进程间通信工具,但使用时需要小心谨慎,确保数据同步和资源管理得当,才能充分发挥其优势。


http://www.ppmy.cn/server/178600.html

相关文章

7. 【Vue实战--孢子记账--Web 版开发】-- 收支分类设置

本篇文章我们一起来实现收支分类功能。收支分类和前篇文章的主币种设置界面大体类似。我们将详细介绍如何创建和管理不同的收支分类&#xff0c;以便用户可以更好地组织和跟踪他们的财务状况。 一、功能 先来看一下原型界面&#xff0c;界面很简单&#xff0c;这里就不多讲解…

Cup:检查容器镜像更新的简单方法

简介 什么是 Cup &#xff1f; Cup 是一个开源工具&#xff0c;旨在简化 Docker 容器的更新管理。它提供了一种快速且高效的方法来检查 Docker 镜像的更新。 主要特点 高效快速&#xff1a;Cup 优化了性能&#xff0c;能够快速检查多个镜像的更新&#xff0c;例如在 Raspberr…

《深度学习》——YOLOv3详解

文章目录 YOLOv3简介YOLOv3核心原理YOLOv3改进YOLOv3网络结构 YOLOv3简介 YOLOv3&#xff08;You Only Look Once, version 3&#xff09;是一种先进的实时目标检测算法&#xff0c;由 Joseph Redmon 和 Ali Farhadi 开发。它在目标检测领域表现出色&#xff0c;具有速度快、精…

【AI模型】深度解析:DeepSeek的联网搜索的实现原理与认知误区

一、大模型的“联网魔法”&#xff1a;原来你是这样上网的&#xff01; 在人工智能这个舞台上&#xff0c;大模型们可是妥妥的明星。像DeepSeek、QWen这些大模型&#xff0c;个个都是知识渊博的“学霸”&#xff0c;推理、生成文本那叫一个厉害。不过&#xff0c;要是论起上网…

模型空间、图纸空间、布局(Layout)之间联系——CAD c#二次开发

在 AutoCAD 的二次开发中&#xff0c;**模型空间&#xff08;Model Space&#xff09;**、**图纸空间&#xff08;Paper Space&#xff09;** 和 **布局&#xff08;Layout&#xff09;** 是三个核心概念&#xff0c;它们的关系及开发中的操作逻辑如下&#xff1a; --- 1. 模…

【论文笔记】Transformer

Transformer 2017 年&#xff0c;谷歌团队提出 Transformer 结构&#xff0c;Transformer 首先应用在自然语言处理领域中的机器翻译任务上&#xff0c;Transformer 结构完全构建于注意力机制&#xff0c;完全丢弃递归和卷积的结构&#xff0c;这使得 Transformer 结构效率更高…

家族族谱管理系统基于Spring Boot

目录 引言 一、系统概述 二、系统架构 三、功能模块 四、技术实现 五、系统特色 六、总结 引言 在数字化浪潮席卷全球的今天&#xff0c;家族文化的传承与延续面临着前所未有的挑战与机遇。传统纸质家谱因保存不便、查询困难、更新滞后等问题&#xff0c;已难以满足现代…

Android Shell上执行可执行文件报错:Permission denied

原因分析 文件系统挂载为noexec Android的某些分区&#xff08;如/sdcard、/storage&#xff09;默认挂载为noexec&#xff0c;禁止直接执行其中的文件。使用mount命令可查看挂载选项&#xff0c;若包含noexec&#xff0c;则该分区下的文件无法执行。 SELinux安全策略限制 SEL…