[Linux] 共享内存
在Linux中,共享内存是一种允许不同进程之间直接交换数据的高效机制。它是IPC(Inter-Process Communication,进程间通信)的一种方式,允许多个进程通过映射同一块物理内存区域来实现数据共享,而无需使用内核来中转数据,从而大大提高了效率。
本文将介绍Linux共享内存的基本概念、使用方法以及在实际开发中的应用。
1. 什么是共享内存
共享内存允许不同进程访问同一块物理内存。多个进程可以将这块共享内存映射到各自的地址空间,进而可以高效地交换数据。这种方式比通过管道、消息队列或套接字传递数据要高效,因为数据直接存在共享内存中,避免了内核的中间转发。
2. 共享内存的特点
- 高效性:共享内存不经过内核转发,因此进程间通信速度极快,特别适合大规模数据交换。
- 易于管理:共享内存通过标准的内存管理方法进行访问和控制,使用起来比较直观。
- 同步问题:由于多个进程可以同时访问同一块内存,可能会出现竞争条件。因此,必须通过某种同步机制(如信号量)来保证数据的一致性。
3. Linux中共享内存的实现
在Linux中,共享内存通常通过shmget
、shmat
、shmdt
等系统调用来进行管理。使用这些调用可以创建、连接、分离和控制共享内存区。
创建共享内存段
首先,进程需要调用shmget
来创建共享内存段。该函数的定义如下:
int shmget(key_t key, size_t size, int shmflg);
key
: 一个标识共享内存段的键值,通常通过ftok
函数生成。size
: 共享内存段的大小,单位为字节。shmflg
: 控制共享内存段创建的标志。常用的标志有:IPC_CREAT
: 如果共享内存段不存在,则创建一个新的共享内存段。IPC_EXCL
: 如果共享内存段已经存在,返回错误。
映射共享内存到进程地址空间
创建共享内存后,进程需要使用shmat
来将共享内存映射到自己的地址空间:
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid
: 通过shmget
返回的共享内存段的标识符。shmaddr
: 可选,指定共享内存的映射地址,通常为NULL
,由系统自动分配。shmflg
: 映射标志,常用值有SHM_RDONLY
(只读)和0
(读写)。
返回值是共享内存段的首地址,进程可以通过该地址进行数据读写。
分离共享内存
当进程不再需要访问共享内存时,可以调用shmdt
将其从进程的地址空间中分离:
int shmdt(const void *shmaddr);
shmaddr
: 共享内存段的首地址。
删除共享内存段
最后,如果共享内存段不再使用,可以调用shmctl
删除它:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid
: 共享内存段的标识符。cmd
: 操作类型,IPC_RMID
表示删除共享内存段。buf
: 一个指向shmid_ds
结构体的指针,通常传入NULL
即可。
4. 共享内存的同步问题
共享内存本身并不提供同步机制,因此在多个进程同时访问共享内存时,必须显式地使用一些同步工具来避免数据竞争。
最常见的同步工具有:
- 信号量(Semaphore):信号量用于控制多个进程对共享资源的访问。可以通过
semget
、semop
等系统调用来使用。 - 互斥锁(Mutex):类似于信号量,但专门用于保证在任意时刻只有一个进程可以访问共享内存。
5. 共享内存的应用场景
- 高速缓存:在多进程应用中,多个进程可能需要访问大量的共享数据。通过共享内存,可以避免数据的复制,从而提高系统性能。
- 数据交换:在多个进程之间频繁交换大量数据时,共享内存能够提供比管道、消息队列更高的效率。
- 分布式计算:多个计算进程可以通过共享内存交换计算结果,在高性能计算中尤为重要。
6. 示例代码:创建和使用共享内存
下面是一个简单的共享内存示例,演示了如何创建共享内存、写入数据、然后读取数据。
ShareMemory.hpp
#pragma once
#include <iostream>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>const std::string gpath = "/home/an/code";
const int gprojId = 0x6666;
//
const int gshmsize = 4096;
mode_t gmode = 0600;std::string ToHex(key_t key)
{char buff[gshmsize];snprintf(buff, sizeof(buff), "0x%x", key);return buff;
}class ShareMemory
{
private:void CreatMemoryHelper(int shmflg){// 1.创建key// ftok()_key = ::ftok(gpath.c_str(), gprojId);if (_key < 0){std::cerr << "ftok error" << std::endl;return;}// 2.int _shmid = ::shmget(_key, gshmsize, shmflg);if (_shmid < 0){std::cerr << "shm get error." << std::endl;return;}}public:ShareMemory(): _shmid(-1),_key(0),_addr(nullptr){}~ShareMemory(){}void CreatMemory(){CreatMemoryHelper(IPC_CREAT | IPC_EXCL | gmode);}void GetShm(){CreatMemoryHelper(IPC_CREAT);}void AttachShm(){_addr = shmat(_shmid, nullptr, 0); // 为什么会失败???if ((long long)_addr == -1){std::cout << "attach error" << std::endl;return;}return;}void DetachShm(){if (_addr != nullptr)::shmdt(_addr);std::cout << "detach done: " << std::endl;}void DeleteShm(){shmctl(_shmid, IPC_RMID, nullptr);}void *GetAddr(){return _addr;}void ShmMeta(){}private:int _shmid;key_t _key;void *_addr;};//临时
ShareMemory shm;
Server.cc
#include <iostream>
#include <unistd.h>
#include "ShareMemory.hpp"int main()
{shm.CreatMemory();shm.AttachShm();std::cout << "server attach done" << std::endl;sleep(10);shm.DetachShm();std::cout << "server detach done" << std::endl;sleep(10);shm.DeleteShm();std::cout << "server delete done" << std::endl;sleep(10);return 0;
}
Client.cc
#include <iostream>
#include "ShareMemory.hpp"int main()
{shm.GetShm();shm.AttachShm();//在这里进行IPCshm.DetachShm();shm.DeleteShm();return 0;
}
7. 总结
Linux共享内存为进程间数据交换提供了一种高效、低延迟的方式。它通过直接映射内存区域来避免了数据的复制和内核的干预,是需要高性能通信的应用程序中不可或缺的技术。然而,共享内存也带来了同步和访问控制的挑战,开发者需要谨慎设计以保证数据一致性和安全性。
相关文章:

[Linux] 共享内存
在Linux中,共享内存是一种允许不同进程之间直接交换数据的高效机制。它是IPC(Inter-Process Communication,进程间通信)的一种方式,允许多个进程通过映射同一块物理内存区域来实现数据共享,而无需使用内核来…...

网络的基础
学习地点(泷羽sec的个人空间-泷羽sec个人主页-哔哩哔哩视频 (bilibili.com)) HTTP协议介绍 HTTP,全称为超文本传输协议(HyperText Transfer Protocol),是用于万维网服务器向本地浏览器传输超文本ÿ…...

金融学期末速成笔记
【拯救者】金融学速成(基础习题) 重点: 市场经济是发达的商品经济。在市场经济条件下,市场机制作为资源配置方式,发挥基础性作用。 除具有商品经济的一般特征外,与商品经济相比,市场经济还具有一些新的特征…...

【Elasticsearch入门到落地】1、初识Elasticsearch
一、什么是Elasticsearch Elasticsearch(简称ES)是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。它使用Java编写,基于Apache Lucene来构建索引和提供搜索功能,是一个分布式、可扩展、近实…...

电子版产品册代替纸质版产品册,开源节流!
在当今数字化时代,企业纷纷寻求创新手段以降低成本、提高效率。纸质版产品册作为传统宣传手段,虽然具有一定的宣传效果,但成本高昂、更新不便、环保压力等问题日益凸显。本文将为您详细解析如何通过采用电子版产品册替代纸质版产品册&#…...

npm i忽略依赖冲突
在使用npm安装依赖时,如果遇到依赖冲突,通常npm会提示错误并阻止安装。但是,如果你想要忽略这些依赖冲突,可以使用以下几种方法: 1.使用--force或-f参数:这个参数会强制npm忽略某些错误,包括依…...

商品,订单业务流程梳理一
业务架构梳理 业务系统介绍 业务商品流程 业务订单流程 业务售后流程 系统架构 技术栈...

Spring中的 bean 标签中的 factory-bean , factory-method
1.首先说说 factory-method 是指定创造实例的工厂方法,用法: factory-method 和 class 配合使用,这时 factory-method 必须是class所指定的类中的一个静态方法,也就是Spring会直接调用 class 所指定的类的静态工厂方法创建一个实例…...

车间管理|基于SprinBoot+vue工厂车间管理系统设计与实现(源码+数据库+文档)
车间管理系统系统 目录 基于SprinBootvue工厂车间管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师&…...

C#实战:使用腾讯云识别服务轻松提取火车票信息
目录 一、腾讯票据单据识别 Invoice OCR服务介绍 二、开发完整流程 2.1 开通文字识别服务 2.2 创建开发者密钥 2.3 创建项目编写代码集成 三、总结 公司内部涉及到车票报销的时候一个个输入火车票信息非常麻烦,尤其是出差比较多的企业,这对于财务人…...

王珊数据库系统概论第六版PDF+第五版课后答案+课件
为了保持科学性、先进性和实用性, 编者在第5版教材基础上对全书内容进行了修改、更新和充实。在科学性方面, 编者在系统篇中增加了第9章关系数据库存储管理, 讲解数据库的逻辑与物理组织方式及索引结构。增加这部分内容有助于学生更好地理解关…...

Spring学习笔记(四)
二十一、Spring事务详解 (一)、Spring基于XML的事务配置 1.环境搭建 1.1 构建maven工程,添加相关技术依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context…...

CALL处 F8的“bug“
看zpchcbd师傅的一篇文章看到了这个比较有趣的点。实操跟着过一遍。 准确来说这个不能说是"bug",这可以是一种"刻意为之"的手段,可以用于加壳、反调试等逆向技术中。 原理: F8步过call的时候,其实是在call的…...

Verilog中的有符号数与无符号数
1. 有符号与无符号最本质的区别在于高位扩展时的扩展规则不同; 对于同一个4‘b1001进行位扩展成8位: 有符号扩展结果为:8’b11111001 无符合扩展结果为: 8b00001001 2. 同第一点,若在运算中没有涉及位扩展,则有符…...

15分钟学 Go 第 47 天 :并发进阶——深入了解Go语言的并发模型!
第47天的学习:并发进阶——深入了解Go语言的并发模型! 目录 Go并发模型简介Goroutines深度讲解Channels的进阶使用Select语句详解并发模型设计模式实战案例分析常见问题与解决方案 1. Go并发模型简介 Go语言以其内置的并发支持而闻名。通过轻量级的g…...

前端代码分析题(选择题、分析题)——this指向、原型链分析
this指向 普通函数:this 的指向由调用方式决定,可以是全局对象、调用该函数的对象,或者显式指定的对象。箭头函数:this 的指向在定义时确定,始终继承自外层函数作用域的 this,不会被调用方式影响。 var obj…...

react 组件应用
文章目录 react 组件react 中组件 hook 函数应用useMemo技术细节(useMemo 钩子函数和 useCallback 钩子函数)小结(依赖性数组应用) react 组件 函数式组件实例及应用场景 实例: 以下是一个简单的函数式组件,用于显示一个欢迎消息。 import React from re…...

mysql 快速解决死锁方式
mysql 快速解决死锁方式 直接寻找并终止导致死锁的具体 SQL 语句是处理死锁的一种有效方法,特别是在高并发环境中。以下步骤和示例展示了如何通过识别、分析和终止长时间运行的 SQL 语句来解决死锁问题。 一、识别那个导致死锁的 SQL 语句 1. 使用 SHOW ENGINE I…...

RabbitMQ 篇-深入了解 RabbitMQ 安装以及 SpringAMQP 的基础使用(声明队列和交换机、发送接收消息、配置 JSON 消息转化器)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 RabbitMQ 初识 1.1 RabbitMQ 安装 2.0 数据隔离 2.1 用户管理 2.2 virtual host 虚拟主机 3.0 SpringAMQP 3.1 RabbitMQ 配置 3.2 发送消息 3.3 接收消息 3.4 Wor…...

在 WPF 中,绑定机制是如何工作的?WPF数据绑定机制解析
在WPF(Windows Presentation Foundation)中,数据绑定机制是其核心功能之一,广泛用于连接应用程序的UI(用户界面)和应用程序的业务逻辑层。数据绑定允许你将UI元素与数据源(如对象、集合或其他数…...

pwn学习笔记(12)--Chunk Extend and Overlapping
pwn学习笔记(12)–Chunk Extend and Overlapping chunk extend 是堆漏洞的一种常见利用手法,通过 extend 可以实现 chunk overlapping(块重叠) 的效果。这种利用方法需要以下的时机和条件: 程序中存在…...

java基础面试题六集合框架
目录 1. List,Set,Map是否继承自collection接口? 2. 说说List,Set,Map三者的区别 3. 写出list、map、set接口的实现类,并说出其特点 4. 常见集合类的区别和适用场景 5. 集合的父类是谁?哪些安全的? 6…...

2024年12月一区SCI-指数-三角优化算法ETO-附Matlab免费代码
引言 本期介绍了一种基于数学概念的元启发式优化算法,称为指数-三角优化算法Exponential-trigonometric optimization algorithm,ETO。该算法基于指数函数和三角函数的复杂组合,于2024年12月最新发表在中JCR1区、 中科院1区 SCI期刊Computer…...

设置服务器ssh连接超时时间
在Linux服务器上,您可以通过修改SSH服务器配置文件来设置SSH连接的超时时间。以下是设置SSH连接超时时间的一些步骤: 打开SSH服务器配置文件。这个文件通常是/etc/ssh/sshd_config。sudo nano /etc/ssh/sshd_config在配置文件中,您可以设置以…...

Dubbo分布式日志跟踪实现
前言 随着越来越多的应用逐渐微服务化后,分布式服务之间的RPC调用使得异常排查的难度骤增,最明显的一个问题,就是整个调用链路的日志不在一台机器上,往往定位问题就要花费大量时间。如何在一个分布式网络中把单次请求的整个调用日…...

EPSON机械手与第三方相机的校准功能设计By python
EPSON机械手与第三方相机的校准功能设计By python 使用Python来实现EPSON机械手与第三方相机的校准功能是一个复杂但可行的任务。这通常涉及以下几个步骤:硬件接口通信、图像处理、标定算法实现和控制逻辑编写。 1. 环境准备 首先,库 pip install numpy opencv-python pyse…...

探索 Java 23:新时代的编程利器
一、引言 随着技术的不断发展,Java 作为一种广泛应用的编程语言也在不断演进。Java 23 的推出带来了许多令人兴奋的新特性和改进,为开发者提供了更多的工具和功能,以应对日益复杂的软件开发挑战。本文将深入介绍 Java 23 的各个方面。 二、J…...

CSS3_3D变换(七)
1、CSS3_3D变换 1.1 3D空间与景深 3D空间:在父元素中将属性transform-style设置为preserve-3d开启3D空间,默认值为flat(开启2D空间); 景深:人眼与平面的距离,产生透视效果,使得效果…...

Mesh网格
Mesh(网格) 定义:Mesh 是一个包含顶点、三角形、顶点法线、UV坐标、颜色和骨骼权重等数据的对象。它定义了3D模型的几何形状。 功能: 顶点(Vertices):构成3D模型的点。 三角形(Triangles)&…...

LeetCode 509.斐波那契数
动态规划思想 五步骤: 1.确定dp[i]含义 2.递推公式 3.初始化 4.遍历顺序 5.打印dp数组 利用状态压缩,简化空间复杂度。在原代码中,dp 数组保存了所有状态,但实际上斐波那契数列的计算只需要前两个状态。因此,我们…...