linux共享内存的使用

news2024/10/7 8:21:04

共享内存可以由多个程序同时访问的内存,能够避免进程间通信过程中的冗余数据拷贝,是IPC中最快的一种,特别适合用来作大块数据的传输。共享内存可以映射到不同的进程空间,这些进程间的数据传递就不再涉及内核。这个过程其实是把同一块物理内存映射到不同进程的虚拟地址,这些进程可以同时对共享内存进行读写。
在这里插入图片描述
共享内存的使用主要分为以下三步:

  1. 创建一个共享内存
  2. 设置共享内存的大小
  3. 将共享内存映射到进程用户空间
    进行到第二步的时候就已经在内核空间创建了一块内存空间,只要再把它映射到进程用户空间就可以使用了。
    在Linux中主要提供了两套接口来使用共享内存,分别是posix接口和system V接口。其中posix接口的可移植性更好。

posix接口

int shm_open(const char *name, int oflag, mode_t mode);//打开一个共享内存文件
int ftruncate(int fildes, off_t length);//设置共享内存的大小
void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);//将共享内存映射到进程地址空间,返回值是共享内存映射到进程空间的地址
int munmap(void *addr, size_t length);//取消内存映射                  
int shm_unlink(const char *name);//删除共享内存

shm_open() 创建并打开一个新的或打开一个现有的 POSIX 共享内存对象。 POSIX 共享内存对象实际上是一个句柄,不相关的进程可以使用它来 mmap(2) 共享内存的同一区域。 shm_unlink() 函数执行相反的操作,删除先前由 shm_open() 创建的对象。

shm_open() 的操作类似于 open。 name 指定要创建或打开的共享内存对象。
oflag 是一个位掩码,它通过将 O_RDONLY 或 O_RDWR 中的一个与以下列出的任意标志进行 OR 运算来创建:

O_RDONLY
以只读模式打开。 以这种方式打开的共享内存对象只能被 mmap(2) 用于读取 (PROT_READ) 访问。
O_RDWR
以读写模式打开。
O_CREATE
如果共享内存对象不存在,则创建它。 对象的用户和组所有权取自调用进程对应的有效ID,对象的权限位按照参数mode的低9位设置,不过在process file mode创建掩码中设置的那些位 (请参阅umask(2))会被清除。 open(2) 中列出了一组可用于定义mode的宏常量。 (这些常量的符号定义可以通过包含<sys/stat.h>来获得。)
一个新的共享内存对象最初的长度为零——对象的大小可以使用 ftruncate 设置。 共享内存对象新分配的字节会自动初始化为 0。
O_EXCL
如果同时指定了 O_CREAT,并且给定name的共享内存对象已经存在,则返回错误。 检查对象是否存在,以及不存在时创建新对象的过程是原子的。此标识是为了避免: 如果对象存在,但是制定了O_CREATE,那么默认的操作是打开该对象,这样就不知道是打开了原有的还是创建了新的,而O_EXCL确保,一定是创建一个新的,否则就要报错
O_TRUNC
如果对象存在,则将其长度大小截断为0

成功完成后,shm_open() 返回一个引用共享内存对象的新文件描述符。

文件描述符通常用于后续调用 ftruncate(用于新创建的对象)和 mmap。 调用 mmap 后,可能会关闭文件描述符而不影响内存映射。

shm_unlink() 的操作类似于 unlink:它删除一个共享内存对象名称,并且一旦所有进程都取消映射该对象(执行unmap),就释放并销毁相关内存区域的内容。 在成功 shm_unlink() 之后,尝试 shm_open() 具有相同名称的对象失败(除非指定了 O_CREAT,在这种情况下会创建一个新的、不同的对象)。

成功时,shm_open() 返回一个文件描述符(一个非负整数)。 成功时,shm_unlink() 返回 0。失败时,两个函数都返回 -1 并设置 errno 以指示错误。

system V 接口

int shmget(key_t key, size_t size, int shmflg);//打开一个共享内存文件
void *shmat(int shmid, const void *shmaddr, int shmflg)//将共享内存映射到进程地址空间
int shmdt(const void *shmaddr);//删除共享内存

posix接口使用示例

生产者消费者模型,一个进程写一个进程读
生产者代码:

/**
 * Simple program demonstrating shared memory in POSIX systems.
 *
 * This is the producer process that writes to the shared memory region.
 *
 * Figure 3.17
 *
 * @author Silberschatz, Galvin, and Gagne
 * Operating System Concepts - Ninth Edition
 * Copyright John Wiley & Sons - 2013
 *
 * modifications by dheller@cse.psu.edu, 31 Jan. 2014
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>

void display(char *prog, char *bytes, int n);

int main(void)
{
  const char *name = "/shm-example";    // file name
  const int SIZE = 4096;        // file size

  const char *message0 = "Studying ";
  const char *message1 = "Operating Systems ";
  const char *message2 = "Is Fun!";
  const char *msg_end  = "\n";

  int shm_fd;        // file descriptor, from shm_open()
  char *shm_base;    // base address, from mmap()
  char *ptr;        // shm_base is fixed, ptr is movable

  /* create the shared memory segment as if it was a file */
  shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
  if (shm_fd == -1) {
    printf("prod: Shared memory failed: %s\n", strerror(errno));
    exit(1);
  }

  /* configure the size of the shared memory segment */
  ftruncate(shm_fd, SIZE);

  /* map the shared memory segment to the address space of the process */
  shm_base = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
  if (shm_base == MAP_FAILED) {
    printf("prod: Map failed: %s\n", strerror(errno));
    // close and shm_unlink?
    exit(1);
  }

  /**
   * Write to the mapped shared memory region.
   *
   * We increment the value of ptr after each write, but we
   * are ignoring the possibility that sprintf() fails.
   */
  display("prod", shm_base, 64);
  ptr = shm_base;
  ptr += sprintf(ptr, "%s", message0);
  ptr += sprintf(ptr, "%s", message1);
  ptr += sprintf(ptr, "%s", message2);
  ptr += sprintf(ptr, "%s", msg_end);
  display("prod", shm_base, 64);

  /* remove the mapped memory segment from the address space of the process */
  if (munmap(shm_base, SIZE) == -1) {
    printf("prod: Unmap failed: %s\n", strerror(errno));
    exit(1);
  }

  /* close the shared memory segment as if it was a file */
  if (close(shm_fd) == -1) {
    printf("prod: Close failed: %s\n", strerror(errno));
    exit(1);
  }

  return 0;
}

void display(char *prog, char *bytes, int n)
{
  printf("display: %s\n", prog);
  for (int i = 0; i < n; i++)
    { printf("%02x%c", bytes[i], ((i+1)%16) ? ' ' : '\n'); }
  printf("\n");
}

消费者:

/**
 * Simple program demonstrating shared memory in POSIX systems.
 *
 * This is the consumer process
 *
 * Figure 3.18
 *
 * @author Gagne, Galvin, Silberschatz
 * Operating System Concepts - Ninth Edition
 * Copyright John Wiley & Sons - 2013
 *
 * modifications by dheller@cse.psu.edu, 31 Jan. 2014
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>

void display(char *prog, char *bytes, int n);

int main(void)
{
  const char *name = "/shm-example";    // file name
  const int SIZE = 4096;        // file size

  int shm_fd;        // file descriptor, from shm_open()
  char *shm_base;    // base address, from mmap()

  /* open the shared memory segment as if it was a file */
  shm_fd = shm_open(name, O_RDONLY, 0666);
  if (shm_fd == -1) {
    printf("cons: Shared memory failed: %s\n", strerror(errno));
    exit(1);
  }

  /* map the shared memory segment to the address space of the process */
  shm_base = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
  if (shm_base == MAP_FAILED) {
    printf("cons: Map failed: %s\n", strerror(errno));
    // close and unlink?
    exit(1);
  }

  /* read from the mapped shared memory segment */
  display("cons", shm_base, 64);    // first as bytes, then as a string
  printf("%s", shm_base);

  /* remove the mapped shared memory segment from the address space of the process */
  if (munmap(shm_base, SIZE) == -1) {
    printf("cons: Unmap failed: %s\n", strerror(errno));
    exit(1);
  }

  /* close the shared memory segment as if it was a file */
  if (close(shm_fd) == -1) {
    printf("cons: Close failed: %s\n", strerror(errno));
    exit(1);
  }

  /* remove the shared memory segment from the file system */
  if (shm_unlink(name) == -1) {
    printf("cons: Error removing %s: %s\n", name, strerror(errno));
    exit(1);
  }

  return 0;
}

void display(char *prog, char *bytes, int n)
{
  printf("display: %s\n", prog);
  for (int i = 0; i < n; i++)
    { printf("%02x%c", bytes[i], ((i+1)%16) ? ' ' : '\n'); }
  printf("\n");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/114635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java高效率复习-Spring[Spring]

前言 Spring的学习还是很简单的&#xff0c;到SpringMVC的时候则会比较复杂了&#xff0c;因为要创建Web项目以及一些Web因素等等。 Spring的简介 Spring入门案例 导入依赖 <packaging>jar</packaging><dependencies><!-- 基于Maven依赖传递性&#x…

[ 代码审计篇 ] Fortify 安装及使用详解(一)Fortify 下载安装并设置语言为中文导出中文报告

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

毕业5年,我买房了

持续坚持原创输出&#xff0c;点击蓝字关注我吧 都说人到30就觉得时间过的很快&#xff0c;这句话确实不假&#xff0c;2022年我已经毕业五年&#xff0c;今年下半年也终于在成都高新区购房了&#xff0c;在这里有了自己的家。 购房对于大多数人来说肯定是人生一件大事吧&…

【Maven基础】单一架构案例(三)

第六节 业务功能&#xff1a;登录 1、显示首页 1.1、流程图 1.2、创建 PortalServlet 1.2.1、创建 Java 类 public class PortalServlet extends ViewBaseServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptio…

NetSuite Decode函数

昨天是平安夜&#xff0c;小家伙仍然为圣诞老人的到来准备了礼物&#xff0c;这是他的传统。每年为了感谢圣诞老人和驯鹿的到来&#xff0c;他都会准备上点心、水果。今年&#xff0c;他认为驯鹿可能需要电力&#xff0c;所以准备了电池给它们享用。 真希望天真一直伴随他的成长…

nestjs学习

某种原因开始学习nestjs&#xff0c;想用nestjs做后端&#xff0c;mongodb做数据库来实现一个微信小程序的后台&#xff0c;开始了哼哧哼哧的爬代码之路。 如果想使用自己写的js或ts工具库&#xff0c;需要使用require进行导入&#xff01;&#xff01;否则找不到文件&#xff…

平衡二叉树的一系列操作:删除、插入(在二叉排序树中插入新结点后,如何保持平衡)、调整平衡等等等

平衡二叉树的插入&#xff08;在二叉排序树中插入新结点后&#xff0c;如何保持平衡&#xff09;1.平衡二叉树的定义2.平衡二叉树的插入&#xff08;调整最小不平衡子树A&#xff09;2.1LL&#xff08;在A的左孩子的左子树中插入导致不平衡&#xff09;2.2RR&#xff08;在A的右…

qt嵌入并运行外部exe

由于项目需要&#xff0c;要实现将一个外部exe运行在qt的窗口中。下面记录一下过程&#xff1a; 首先就是在qt中创建一个新项目 由于我这里没有用到画布&#xff0c;所以没有勾选Generate form 然后就会自动生成一个可运行的代码 然后将我下边的代码替换粘贴进去 #includ…

RabbitMQ 第二天 高级 7 RabbitMQ 高级特性 7.5 死信队列

RabbitMQ 【黑马程序员RabbitMQ全套教程&#xff0c;rabbitmq消息中间件到实战】 文章目录RabbitMQ第二天 高级7 RabbitMQ 高级特性7.5 死信队列7.5.1 死信队列概述7.5.2 代码实现7.5.3 小结第二天 高级 7 RabbitMQ 高级特性 7.5 死信队列 7.5.1 死信队列概述 死信队列&am…

[LeetCode周赛复盘] 第 325 场周赛20221225

[LeetCode周赛复盘] 第 325 场周赛20221225 一、本周周赛总结二、 [Easy] 6269. 到目标字符串的最短距离1. 题目描述2. 思路分析3. 代码实现三、[Medium] 6270. 每种字符至少取 K 个1. 题目描述2. 思路分析3. 代码实现四、[Medium] 6271. 礼盒的最大甜蜜度1. 题目描述2. 思路分…

<Linux线程同步>——《Linux》

目录 1. Linux线程同步 1.1条件变量 1.2同步概念与竞态条件 1.3条件变量函数 1.4 为什么pthread_ cond_ wait 需要互斥量? 1.5 条件变量使用规范 后记&#xff1a;●由于作者水平有限&#xff0c;文章难免存在谬误之处&#xff0c;敬请读者斧正&#xff0c;俚语成篇&am…

论文阅读技巧

文献阅读思维 为什么你花了大量的时间来看文献却没有收获&#xff1f;那是因为你漫无目的的看文献&#xff0c;能有什么收获&#xff1f;所以我们要带着两个问题有目的的阅读文献。这个目的是什么&#xff1f;就是为了给自己找创新思路。同时在看摘要的时候你问自己第一个问题…

Mac (M1)搭建QGC地面站环境

之前朋友介绍了一个活&#xff0c;刚开始以为是针对树莓派进行二次开发。到了之后才发现&#xff0c;全新的领域&#xff0c;抱着试一试的想法就蛮答应了下来。后来在搭建环境的过程了一路受挫&#xff0c;不过就在写此文前几分钟&#xff0c;终于看到了成功的标志&#xff0c;…

2022年春秋杯网络安全联赛-冬季赛RE部分题解

easy_python python字节码 逻辑整理后就给flag flag [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175] for i in rang…

C++进阶(一)C++新特性:智能指针、右值引用、lambda、多线程操作、function和bind、可变模板参数

layout: post title: C进阶&#xff08;一&#xff09;C新特性&#xff1a;智能指针、右值引用、lambda、多线程操作、function和bind、可变模板参数 description: C进阶&#xff08;一&#xff09;C新特性&#xff1a;智能指针、右值引用、lambda、多线程操作、function和bind…

圣诞节来啦,快把这个动态爱心送个那个TA

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

_15LeetCode代码随想录算法训练营第十五天-C++二叉树

_15LeetCode代码随想录算法训练营第十五天-C二叉树 题目列表 110.平衡二叉树257.二叉树的所有路径404.左叶子之和 110.平衡二叉树 题目 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每…

雪花算法和uuid比较

1. 雪花算法 ​ 现在的服务基本是分布式、微服务形式的&#xff0c;而且大数据量也导致分库分表的产生&#xff0c;对于水平分表就需要保证表中 id 的全局唯一性。对于 MySQL 而言&#xff0c;一个表中的主键 id 一般使用自增的方式&#xff0c;但是如果进行水平分表之后&…

结构体(10)

目录 1、结构体的声明 1、结构体的声明 2、结构体变量的定义和初始化 2、结构体成员的访问 3、结构体传参 1、结构体的声明 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1、结构体的声明 例如&#xff1a;描述一个学生 注…

KOOM线上APM监控最全剖析

APM&#xff0c;全称是Application Performance Management&#xff0c;也就是应用性能管理&#xff0c;这与我们平时写的业务可能并不相关&#xff0c;但是却承载着App线上稳定的责任。当一款App发布到线上之后&#xff0c;不同的用户有不同场景&#xff0c;一旦App出现了问题…