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

[Linux] 共享内存

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

本文将介绍Linux共享内存的基本概念、使用方法以及在实际开发中的应用。


1. 什么是共享内存

共享内存允许不同进程访问同一块物理内存。多个进程可以将这块共享内存映射到各自的地址空间,进而可以高效地交换数据。这种方式比通过管道、消息队列或套接字传递数据要高效,因为数据直接存在共享内存中,避免了内核的中间转发。

2. 共享内存的特点

  • 高效性:共享内存不经过内核转发,因此进程间通信速度极快,特别适合大规模数据交换。
  • 易于管理:共享内存通过标准的内存管理方法进行访问和控制,使用起来比较直观。
  • 同步问题:由于多个进程可以同时访问同一块内存,可能会出现竞争条件。因此,必须通过某种同步机制(如信号量)来保证数据的一致性。

3. Linux中共享内存的实现

在Linux中,共享内存通常通过shmgetshmatshmdt等系统调用来进行管理。使用这些调用可以创建、连接、分离和控制共享内存区。

创建共享内存段

首先,进程需要调用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):信号量用于控制多个进程对共享资源的访问。可以通过semgetsemop等系统调用来使用。
  • 互斥锁(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中&#xff0c;共享内存是一种允许不同进程之间直接交换数据的高效机制。它是IPC&#xff08;Inter-Process Communication&#xff0c;进程间通信&#xff09;的一种方式&#xff0c;允许多个进程通过映射同一块物理内存区域来实现数据共享&#xff0c;而无需使用内核来…...

网络的基础

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

金融学期末速成笔记

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

【Elasticsearch入门到落地】1、初识Elasticsearch

一、什么是Elasticsearch Elasticsearch&#xff08;简称ES&#xff09;是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。它使用Java编写&#xff0c;基于Apache Lucene来构建索引和提供搜索功能&#xff0c;是一个分布式、可扩展、近实…...

电子版产品册代替纸质版产品册,开源节流!

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

npm i忽略依赖冲突

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

商品,订单业务流程梳理一

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

Spring中的 bean 标签中的 factory-bean , factory-method

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

车间管理|基于SprinBoot+vue工厂车间管理系统设计与实现(源码+数据库+文档)

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

C#实战:使用腾讯云识别服务轻松提取火车票信息

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

王珊数据库系统概论第六版PDF+第五版课后答案+课件

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

Spring学习笔记(四)

二十一、Spring事务详解 &#xff08;一&#xff09;、Spring基于XML的事务配置 1.环境搭建 1.1 构建maven工程&#xff0c;添加相关技术依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context…...

CALL处 F8的“bug“

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

Verilog中的有符号数与无符号数

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

15分钟学 Go 第 47 天 :并发进阶——深入了解Go语言的并发模型!

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

前端代码分析题(选择题、分析题)——this指向、原型链分析

this指向 普通函数&#xff1a;this 的指向由调用方式决定&#xff0c;可以是全局对象、调用该函数的对象&#xff0c;或者显式指定的对象。箭头函数&#xff1a;this 的指向在定义时确定&#xff0c;始终继承自外层函数作用域的 this&#xff0c;不会被调用方式影响。 var obj…...

react 组件应用

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

mysql 快速解决死锁方式

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

RabbitMQ 篇-深入了解 RabbitMQ 安装以及 SpringAMQP 的基础使用(声明队列和交换机、发送接收消息、配置 JSON 消息转化器)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 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&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;数据绑定机制是其核心功能之一&#xff0c;广泛用于连接应用程序的UI&#xff08;用户界面&#xff09;和应用程序的业务逻辑层。数据绑定允许你将UI元素与数据源&#xff08;如对象、集合或其他数…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...