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

linux进程间通信之共享内存(mmap,shm_open)

         共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进 程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。如果某个 进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。 Linux 操作系统的进程通常使用的是虚拟内存,虚拟内存空间是有由物理内存映射而来的。System V 共 享内存能够实现让两个或多个进程访问同一段物理内存空间,达到数据交互的效果。

共享内存和其他进程间数据交互方式相比,有以下几个突出特点:
        1.速度快,因为共享内存不需要内核控制,所以没有系统调用。而且没有向内核拷贝数据的过程,所以效率和前面几个相比是最快的,可以用来进行批量数据的传输,比如图片。
        2. 没有同步机制,需要借助 Linux 提供其他工具来进行同步,通常使用信号灯。
使用共享内存的步骤:
1. 调用 shmget() 创建共享内存段 id
2. 调用 shmat() id 标识的共享内存段加到进程的虚拟地址空间,
3. 访问加入到进程的那部分映射后地址空间,可用 IO 操作读写。

        在Linux系统中,有多种方式可以实现共享内存,其中一种是使用POSIX共享内(posix_shm)。POSIX共享内存有两种方法:

1.内存映射文件

        先用open函数打开一个文件,然后调用mmap函数把得到的描述符映射到当前进程地址空间中。这种方式访问速度相对较慢,因为需要内核同步或异步更新到文件系统中。

(1)代码

#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/mman.h>  
#include <unistd.h>  int main() {  // 打开文件  int fd = open("example.txt", O_RDWR);  if (fd == -1) {  perror("Error opening file");  exit(EXIT_FAILURE);  }  // 获取文件大小  struct stat sb;  if (fstat(fd, &sb) == -1) {  perror("Error getting the file size");  exit(EXIT_FAILURE);  }  off_t length = sb.st_size; // 文件大小,单位是字节  // 映射内存到进程的地址空间  char* map = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  if (map == MAP_FAILED) {  perror("Error mmapping the file");  exit(EXIT_FAILURE);  }  // 打印映射的内存内容,即文件内容  for (off_t i = 0; i < length; i++) {  printf("%c", map[i]); // 打印每个字符,即文件内容  }  printf("\n");  // 释放内存映射和文件描述符  if (munmap(map, length) == -1) {  perror("Error un-mmapping the file");  exit(EXIT_FAILURE);  }  close(fd);  return 0;  
}

(2)注解

  • open函数用于打开文件,其返回值是文件描述符。如果打开失败,则返回-1。第二个参数O_RDWR表示以读写模式打开文件。
  • fstat函数用于获取文件的大小,其返回值是stat结构体,其中st_size成员表示文件大小(单位是字节)。如果获取失败,则返回-1。
  • mmap函数用于将文件映射到进程的地址空间。第一个参数是映射区域的起始地址,通常为NULL。第二个参数是映射区域的长度。第三个参数是保护标志,这里设置为读、写和共享(可读、可写、可被其他进程共享)。第四个参数是映射对象的类型,这里设置为共享内存。第五个参数是文件描述符。第六个参数是文件映射的偏移量。如果映射成功,则返回映射区域的指针;否则返回MAP_FAILED。
  • munmap函数用于释放内存映射。第一个参数是映射区域的指针。第二个参数是映射区域的长度。如果释放成功,则返回0;否则返回-1。

2.共享内存对象

        先用shm_open打开一个Posix IPC名字(也可以是文件系统中的一个路径名),然后调用mmap将返回的描述符映射到当前进程的地址空间。

(1)代码

#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/mman.h>  
#include <unistd.h>  #define SHM_SIZE 1024  // 共享内存大小  int main() {  int fd;  void *map_ptr;  // 打开共享内存对象,以读写模式打开,不创建新对象,如果对象不存在则返回-1  fd = shm_open("/Posix IPC", O_RDWR | O_CREAT, 0666);  if (fd == -1) {  perror("shm_open");  exit(EXIT_FAILURE);  }  // 调整共享内存对象的大小,这里将其设置为1024字节  if (ftruncate(fd, SHM_SIZE) == -1) {  perror("ftruncate");  exit(EXIT_FAILURE);  }  // 将共享内存对象的描述符映射到当前进程的地址空间,map_ptr指向的就是这块内存的起始地址  map_ptr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  if (map_ptr == MAP_FAILED) {  perror("mmap");  exit(EXIT_FAILURE);  }  // 现在可以在map_ptr指向的内存区域进行读写操作了,这就像操作普通的内存一样简单  // ... 写入数据到 map_ptr 指向的内存区域 ...  // ... 从 map_ptr 指向的内存区域读取数据 ...  // 当进程不再需要访问共享内存时,可以通过调用munmap来撤销内存映射,参数是map_ptr和映射的长度  if (munmap(map_ptr, SHM_SIZE) == -1) {  perror("munmap");  exit(EXIT_FAILURE);  }  // 关闭共享内存对象的描述符,然后删除该对象,参数是fd和0,表示删除成功返回0,否则返回-1  if (close(fd) == -1) {  perror("close");  exit(EXIT_FAILURE);  }  if (shm_unlink("/my_shm") == -1) {  perror("shm_unlink");  exit(EXIT_FAILURE);  }  return 0;  
}

 (2)注解

  • shm_open函数用于打开或创建共享内存对象。第一个参数是对象名,第二个参数是打开模式(这里使用读写模式),第三个参数是权限设置(这里设置为0666,表示所有用户都可以读写这个对象)。如果对象不存在,shm_open会创建一个新对象。如果创建成功,shm_open会返回一个文件描述符。如果失败,返回-1。
  • ftruncate函数用于调整共享内存对象的大小。第一个参数是文件描述符,第二个参数是新的文件大小。这里将文件大小设置为1024字节。如果成功,ftruncate返回0;否则返回-1。
  • mmap函数用于将共享内存对象的描述符映射到当前进程的地址空间。第一个参数是映射区域的起始地址(通常为NULL),第二个参数是映射区域的长度,第三个参数是保护标志(这里设置为读、写和共享),第四个参数是映射对象的类型(这里设置为共享内存),第五个参数是文件描述符,第六个参数是文件映射的偏移量。如果映射成功,mmap返回映射区域的指针;否则返回MAP_FAILED。

3.总结

        在使用共享内存时,需要注意同步问题。因为多个进程可以同时操作共享内存,可能导致数据不一致。互斥锁和信号量等同步机制可以解决这个问题。

        共享内存是一种非常有效的进程间通信方式,尤其适用于大数据量的传输和频繁的通信需求。但是,使用共享内存时需要注意同步和数据一致性问题。

相关文章:

linux进程间通信之共享内存(mmap,shm_open)

共享内存&#xff0c;顾名思义就是允许两个不相关的进程访问同一个逻辑内存&#xff0c;共享内存是两个正在运行的进 程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中&#xff0c…...

C/C++---------------LeetCode第1748.唯一元素的和

唯一元素的和 题目及要求哈希算法暴力算法在main里使用 题目及要求 给你一个整数数组 nums 。数组中唯一元素是那些只出现 恰好一次 的元素。 请你返回 nums 中唯一元素的 和 。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,2] 输出&#xff1a;4 解释&#xff1a;唯…...

什么是好用的HR人才测评?

对于HR来说&#xff0c;选用一个合适的测评工具&#xff0c;我想不外乎以下几点&#xff1a; 1、成本可控 不是所有的HR都能申请到足够的资金&#xff0c;去做专业的人才测评&#xff0c;尤其是中小企业&#xff0c;这可是一笔不小 的开支。即使是基层普通岗位的成本&#xf…...

【ARM Trace32(劳特巴赫) 使用介绍 5 -- Trace32 scan dump 详细介绍】

文章目录 1.1 JTAG 测试逻辑架构1.2 D型扫描触发器1.2.1 全扫描介绍1.3 IR 寄存器1.4 TDR(Test data registers)1.4.1 TDR 的实现1.4.1.1 Bypass Register1.4.1.2 Boundary-scan register1.5 Scan Dump1.5.1 soft fusion1.1 JTAG 测试逻辑架构 图 1-1 片上测试逻辑概念图 如前面…...

Java版B/S架构云his医院信息管理系统源码(springboot框架)

一、技术框架 ♦ 前端&#xff1a;AngularNginx ♦ 后台&#xff1a;JavaSpring&#xff0c;SpringBoot&#xff0c;SpringMVC&#xff0c;SpringSecurity&#xff0c;MyBatisPlus&#xff0c;等 ♦ 数据库&#xff1a;MySQL MyCat ♦ 缓存&#xff1a;RedisJ2Cache ♦ 消息队…...

面试经典(2/150)移除元素

面试经典(2/150)移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要…...

基于JavaWeb+SpringBoot+掌上社区疫苗微信小程序系统的设计和实现

基于JavaWebSpringBoot掌上社区疫苗微信小程序系统的设计和实现 源码获取入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种…...

python_主动调用其他类的成员

# 主动调用其他类的成员 # 方式一: class Base(object):def f1(self):print("5个功能") class Foo(object):def f1(self):print("3个功能")# Base.实例方法(自己传self),与继承无关Base.f1(self)obj Foo() obj.f1()print("#"*20)# 方式二:按照类…...

Pytorch部分报错问题

一、存在问题 1.链接库报错 问题报错&#xff1a;undefined symbol: __nvJitLinkAddData_12_1, version libnvJitLink.so.12 2.GPU不能使用 问题报错&#xff1a;在torch安装后测试gpu是否可用 torch.cuda.is_available() false 返回false 问题分析&#xff1a; 可能是…...

cmmlu数据处理

cmmlu数据处理 数据处理数据地址代码解析数据处理 from glob import glob import pandas as pd from tqdm import tqdmtrain_data_path_list = glob("test/*") val_data_path_list = glob("dev/*") tran_data = pd.<...

【ARM Trace32(劳特巴赫) 使用介绍 2.2 -- TRACE32 进阶命令之 DIAG 弹框命令】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 上篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 2.1 – TRACE32 Practice 脚本 cmm 脚本学习】 下篇文章&#xff1a;【ARM Trace32(劳特巴赫) 使用介绍 3 - trace32 访问运行时的内存】 文章目录 DIALOG.OK 命令DIA…...

黑马程序员微服务 分布式搜索引擎3

分布式搜索引擎03 0.学习目标 1.数据聚合 **聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售…...

Python正则表达式学习笔记(入门)

1. 介绍 正则表达式是一种强大的模式匹配工具&#xff0c;用于处理文本数据。在Python中&#xff0c;我们使用re模块来操作正则表达式。 2. 基本语法 建议先看 "5. re模块函数"了解search和match的区别"和 2.3 特殊字符转义"了解如何应对特殊符号 2.1 字…...

C++核心编程 day09 类型转换、异常、输入输出流

C核心编程 day09 类型转换、异常、输入输出流 1. 类型转换2. 异常2.1 异常语法2.2 C标准异常库 3. 输入输出流3.1 输入输出流概念以及流类库3.2 标准输入流3.3 标准输出流3.4 文件读写 1. 类型转换 C中的类型转换有四类&#xff0c;分别是静态转换、动态转换、常量转换、重新解…...

Docker安装PostgreSQL

拉取镜像 docker pull postgres 运行容器 docker run --name postgres-db -e TZPRC -e POSTGRES_USERroot -e POSTGRES_DBdatabase -e POSTGRES_PASSWORD123456 -p 5432:5432 -v /Users/xiaoping/byx/postgresql/data:/var/lib/postgresql/data -d postgres run&#xff0c…...

py并发编程实践-demo

需求 已知条件&#xff1a;appX -请求-> api 多进程实现并发请求api 给定app应用列表&#xff0c;请求api核数 from datetime import datetime, timedelta from multiprocessing import Processclass ProcessTest(object):"""多进程并发请求API&#xff…...

1-2 暴力破解-模拟

模拟&#xff1a;根据题目要求编写代码 可分为&#xff1a;图形排版&#xff08;根据某种规则输出特定图形&#xff09;、日期问题、其他模拟 一.图形排版 1.输出梯形&#xff08;清华大学&#xff09; 法一&#xff1a;等差数列 分析&#xff1a;每行的星号个数为等差数列2n2…...

机器学习中的Bagging思想

Bagging&#xff08;Bootstrap Aggregating&#xff09;是机器学习中一种集成学习方法&#xff0c;旨在提高模型的准确性和稳定性。Bagging的思想源自于Bootstrap采样技术&#xff0c;其基本原理如下&#xff1a; Bootstrap采样&#xff1a; Bagging的核心思想是通过对原始数据…...

基于PyTorch搭建你的生成对抗性网络

前言 你听说过GANs吗&#xff1f;还是你才刚刚开始学&#xff1f;GANs是2014年由蒙特利尔大学的学生 Ian Goodfellow 博士首次提出的。GANs最常见的例子是生成图像。有一个网站包含了不存在的人的面孔&#xff0c;便是一个常见的GANs应用示例。也是我们将要在本文中进行分享的…...

ROS话题(Topic)通信:自定义msg - 例程与讲解

在 ROS 通信协议中&#xff0c;数据是以约定好的结构传输的&#xff0c;即数据类型&#xff0c;比如Topic使用的msg&#xff0c;Service使用的srv&#xff0c;ROS 中的 std_msgs 封装了一些原生的数据类型&#xff0c;比如&#xff1a;Bool、Char、Float32、Int64、String等&am…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...