文章目录

  • linux 共享内存操作(shm_open)
    • 一、背景
    • 二、函数使用说明
      • shm_open
      • ftruncate(改变文件大小)
      • mmap共享内存
    • 三、示例代码
      • 创建内存共享文件并写入数据
      • 打开内存共享文件读数据
    • 四、问题总结
      • shm_write.c:(.text+0x18): undefined reference to `shm_open'
        • 编译链接库:-lz -lrt -lm -lc都是什么库
    • 五、参考

linux 共享内存操作(shm_open)

一、背景

在linux系统开发当中,时常需要在多个进程之间交换数据,在多个进程之间交换数据,有很多方法,但最高效的方法莫过于共享内存。

共享内存并不是从某一进程拥有的内存中划分出来的;进程的内存总是私有的。共享内存是从系统的空闲内存池中分配的,希望访问它的每个进程连接它。这个连接过程称为映射,它给共享内存段分配每个进程的地址空间中的本地地址。

linux共享内存是通过tmpfs文件系统来实现的,tmpfs文件系的目录为/dev/shm,/dev/shm是驻留在内存 RAM 当中的,因此读写速度与读写内存速度一样,/dev/shm的容量默认尺寸为系统内存大小的一半大小,使用df -h命令可以看到。

root@i-3t537lcq:~# free -htotal        used        free      shared  buff/cache   available
Mem:          1.9Gi       226Mi       175Mi        20Mi       1.5Gi       1.5Gi
Swap:         2.0Gi        62Mi       1.9Gi
root@i-3t537lcq:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            952M     0  952M   0% /dev
tmpfs           199M  1.4M  198M   1% /run
/dev/vda2        50G   13G   35G  27% /
tmpfs           994M   16K  994M   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           994M     0  994M   0% /sys/fs/cgroup
tmpfs           199M     0  199M   0% /run/user/0
/dev/loop2       64M   64M     0 100% /snap/core20/1778
/dev/loop7       50M   50M     0 100% /snap/snapd/17950
/dev/loop8      138M  138M     0 100% /snap/lxd/24239
/dev/loop4      145M  145M     0 100% /snap/lxd/24323
/dev/loop5       56M   56M     0 100% /snap/core18/2679
/dev/loop3       64M   64M     0 100% /snap/core20/1822
/dev/loop1       50M   50M     0 100% /snap/snapd/18357
/dev/loop9       56M   56M     0 100% /snap/core18/2697
root@i-3t537lcq:~#

实际上它并不会真正的占用这块内存,如果/dev/shm/下没有任何文件,它占用的内存实际上就是0字节,仅在使用shm_open文件时,/dev/shm才会真正占用内存。

二、函数使用说明

Linux的共享内存提供了进程之间共享数据的一种方法,可以避免进程之间的数据复制。Linux的共享内存API有两套,即POSIX共享内存和System V共享内存。POSIX共享内存其实是基于mmap实现的。

共享内存一般基本操作流程如下:

  1. 使用shm_open来新建或者打开一个共享内存
  2. 如果是创建一个新的共享内存对象,那么调用ftruncate设置共享内存对象的最大大小
  3. 使用mmap将共享内存映射到进程的地址空间中,然后操作共享内存
  4. 操作完毕后,使用munmap解除映射。解除映射后,本进程就不能再访问共享内存,但共享内存对象依然还是存在的
  5. 调用close关闭shm_open返回的文件描述符。如果进程修改了共享内存,那么在close之前可一调用fsync来同步。
  6. 如果没有任何进程再访问共享内存对象,可以调用shm_unlink来删除共享内存对象

在Linux系统使用共享内存,POSIX 为创建、映射、同步和取消共享内存段提供五个入口点:

int shm_open(const char *name, int oflag, mode_t mode);
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);
int ftruncate(int fd, off_t length);
  • shm_open():创建共享内存段或连接到现有的已命名内存段。这个系统调用返回一个文件描述符。
    shm_open最主要的操作也是默认的操作就是在/dev/shm/下面,建立一个文件。
  • mmap():把共享内存段映射到进程的内存。这个系统调用需要 shm_open() 返回的文件描述符,它返回指向内存的指针。
  • shm_unlink():根据(shm_open() 返回的)文件描述符,删除共享内存段。实际上,这个内存段直到访问它的所有进程都退出时才会删除,这与在 UNIX 中删除文件很相似。但是,调用 shm_unlink() (通常由原来创建共享内存段的进程调用)之后,其他进程就无法访问这个内存段了。
  • munmap():作用与 mmap() 相反。
  • msync():用来让共享内存段与文件系统同步 — 当把文件映射到内存时
  • ftruncate(改变文件大小)
    参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。
    ftruncate函数是用来截断指定文件的一个系统调用,它可以改变指定文件的大小.当指定的文件的大小比原先的大时,那么多余的部分将会以0填充.
    如果原来的文件大小比参数length大,则超过的部分会被删去。

文件名字是用户自己输入的。另外一定要用ftruncate把文件大小于设置为共享内存大小。

shm_open

int shm_open(const char *name, int oflag, mode_t mode);

功能说明:shm_open 用于创建或者打开共享内存文件。shm_open 也许仅仅是系统函数open的一个包装,不同之处就是shm_open操作的文件一定是位于tmpfs文件系统里的,常见的Linux发布版的tmpfs文件系统的存放目录就是/dev/shm

用shm_open 创建的文件,如果不调用此函数(shm_unlink)删除,会一直存在于/dev/shm目录里,直到操作系统重启或者调用linux命令rm来删除为止。

返回值:成功返回fd>0, 失败返回fd<0

参数说明:

name:要打开或创建的共享内存文件名,由于shm_open 打开或操作的文件都是位于/dev/shm目录的,因此name不能带路径,例如:/var/myshare 这样的名称是错误的,而 myshare 是正确的,因为 myshare 不带任何路径。如果你一定要在name添加路径,那么,请在/dev/shm目录里创建一个目录,例如,如果你想创建一个 bill/myshare 的共享内存文件,那么请先在/dev/shm目录里创建 bill这个子目录,由于不同厂家发布的linux系统的tmpfs的位置也许不是/dev/shm,因此带路径的名称也许在别的环境下打开不成功。

oflag:打开的文件操作属性:O_CREAT、O_RDWR、O_EXCL的按位或运算组合

mode:文件共享模式,例如 0777

代码验证demo

yum install gcc

ftruncate(改变文件大小)

ftruncate(改变文件大小)
定义函数 int ftruncate(int fd,off_t length);

  • 函数说明
    ftruncate()会将参数fd指定的文件大小改为参数length指定的大小。
    参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。
    如果原来的文件大小比参数length大,则超过的部分会被删去。

  • 返回值
    执行成功则返回0,失败返回-1,错误原因存于errno。

  • 错误代码
    EBADF 参数fd文件描述词为无效的或该文件已关闭。
    EINVAL 参数fd 为一socket 并非文件,或是该文件并非以写入模式打开。

mmap共享内存

Linux的共享内存提供了进程之间共享数据的一种方法,可以避免进程之间的数据复制。Linux的共享内存API有两套,即POSIX共享内存和System V共享内存。POSIX共享内存其实是基于mmap实现的。

   #include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);int munmap(void *addr, size_t length);

mmap在调用进程的地址空间中映射一段内存。当参数文件描述符fd为-1时,并在flags中指定MAP_ANONYMOUS,就会生成匿名映射,这种内存映射没有后台文件,可在fork的父子继承中共享(子进程调用execl后不再共享),这也是常用的共享内存手段。当fd参数为某特定文件时,就产生文件映射,不同进程映射统一文件可实现映射区域内存共享的目的。进程对共享内存的操作会在msync调用或者munmap调用后同步到后台文件。

三、示例代码

创建内存共享文件并写入数据

shm_write.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>char buf[10];
char *ptr;int main()
{int fd;fd = shm_open("shm_region", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);if (fd < 0){printf("error open shm_region\n");return 0;}ftruncate(fd, 10);ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (ptr == MAP_FAILED){printf("error map\n");return 0;}*ptr = 0x12;return 0;
}

编译:

gcc -lrt -o  shm_write  shm_write.c

使用hexdump读取共享内存内容:

hexdump /dev/shm/shm_region

打开内存共享文件读数据

shm_read.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
char buf[10];
char *ptr;
int main()
{int fd;fd = shm_open("shm_region", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);if (fd < 0){printf("error open shm_region\n");return 0;}ftruncate(fd, 10);ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (ptr == MAP_FAILED){printf("error map\n");return 0;}while (*ptr != 0x12);printf("ptr : %d\n", *ptr);return 0;
}

编译:

gcc -lrt -o  shm_read  shm_read.c

执行结果:

[root@dev c]# ./shm_read
ptr : 18
[root@dev c]#

四、问题总结

shm_write.c:(.text+0x18): undefined reference to `shm_open’

问题描述:
执行编译,文件内容包含shm_open方法

 gcc -o shm_write  shm_write.c

报错:shm_write.c:(.text+0x18): undefined reference to `shm_open’

问题分析:
没有找到函数定义,需要 指定动态链接库。

man shm_open

解决方法:
编译参数添加 -lrt

gcc -lrt -o  shm_write  shm_write.c

编译链接库:-lz -lrt -lm -lc都是什么库

-lz 压缩库(Z)
-lrt 实时库(real time):shm_open系列
-lm 数学库(math)
-lc 标准C库(C lib)
-dl ,是显式加载动态库的动态函数库

五、参考

linux 共享内存 shm_open ,mmap的正确使用
原文链接:https://blog.csdn.net/ababab12345/article/details/102931841
Linux编程之共享内存
参考URL: https://blog.csdn.net/rangzh/article/details/112002554

linux 共享内存操作(shm_open、mmap、编译链接库:-lz -lrt -lm -lc都是什么库)相关推荐

  1. Linux环境下gcc编译链接库-lz -lrt -lm -lc都是什么库?

    编译链接库:-lz -lrt -lm -lc都是什么库 -lz      压缩库(Z) -lrt     实时库(real time):shm_open系列 -lm     数学库(math) -lc ...

  2. linux的各种自带库-lz -lrt -lm -lc都是什么库

    编译链接库:-lz -lrt -lm -lc都是什么库 lz      压缩库(Z) lrt     实时库(real time):shm_open系列 lm     数学库(math) lc     ...

  3. linux 编译链接库:-lz -lrt -lm -lc

    -lz 压缩库(Z) -lrt 实时库(real time):shm_open系列 -lm 数学库(math) -lc 标准C库(C lib) -dl ,是显式加载动态库的动态函数库

  4. Linux共享内存(二)

    Linux共享内存编程实例 原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119 /*共享内存允许两个或多个进程进程共享同一块 ...

  5. 【Linux共享内存】

    Linux共享内存 一.基本概念 二.常用函数 1. shm_open 2. mmap 3. munmap 4. shm_unlink 5. ftruncate 三.使用示例 四.share内存不足解 ...

  6. c++ 共享内存_关于Linux共享内存的实验 [二] - 原因

    关于Linux共享内存的实验 [一] 上文采用的"删文件"和"杀进程"的方法主要是为了快速演示实验现象,但这种做法不利于通过调试手段进一步探究其内在的逻辑.为此 ...

  7. linux的共享内存,linux共享内存实际在哪里?

    我只想知道共享内存驻留在Linux系统中的位置?它在物理内存还是虚拟内存中?linux共享内存实际在哪里? 我知道有关进程的虚拟内存发送信箱,他们从不同的工艺处理和流程没有看到对方的记忆,但我们可以利 ...

  8. 共享内存映射之mmap()函数详解

    转 共享内存映射之mmap()函数详解 /span> 查看全文 http://www.taodudu.cc/news/show-3175071.html 相关文章: 子集生成(二进制法,逐步生成 ...

  9. linux 共享内存_盘点那些linux 后台开发类常见问题及知识点

    一.linux和os: netstat :显示网络状态 tcpdump:主要是截获通过本机网络接口的数据,用以分析.能够截获当前所有通过本机网卡的数据包.它拥有灵活的过滤机制,可以确保得到想要的数据. ...

最新文章

  1. 太难了…期待一切都能赶快好起来吧
  2. UVa 11636 Hello World!
  3. LeetCode 672. 灯泡开关 Ⅱ(枚举)
  4. java http的get,post请求
  5. Android 系统性能优化(75)---MTK 平台perfomance问题的基本信息确认
  6. vsftp pam mysql_实验记录:vsftp整合mysql-pam管理虚拟账号
  7. seam中格式化文本的处理
  8. alien rpm deb,ubuntu下安装jdk过程及遇到的问题
  9. UniCode编码表 对照表
  10. 工具-python实现电影字幕的自动翻译
  11. Android TextView 字体颜色渐变
  12. 第11章-ThreadSpecificStorage
  13. 战地5离线bot模式_战地2怎么增加bot
  14. 打印机驱动的PCL与PS的区别
  15. Android系统基础介绍
  16. SpaceShooter打飞机教程笔记(二)
  17. python实现base64解码_Python实现base64编码解码
  18. mmdection的安装、测试,心酸历程
  19. 论文研读 —— 5. FaceNet A Unified Embedding for Face Recognition and Clustering (2/3)
  20. 健康管理系统第六天(移动端开发之体检预约_经典五表联查_调用阿里云提供的短信服务进行短信验证码发送)

热门文章

  1. CVPR2022 oral | MetaFormer才是探索Transformer的源泉,衍生PoolFormer速度喜人
  2. AC3/EAC3格式总结
  3. 迅雷java_Java 仿迅雷多线程下载
  4. ZZULIOJ:1668: 画个圈圈诅咒他
  5. Win7添加快速启动栏
  6. Android号码匹配位数修改 来电显示不匹配
  7. vue 插件方式引入混入
  8. 容联入选新基建产业独角兽TOP100
  9. mysql 高并发下查询很慢_MySQL-高并发优化
  10. 台达PLC如何实现远程上下载程序及远程更新参数