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

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

文章目录

  • 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

http://www.lryc.cn/news/18434.html

相关文章:

  • 做出改变:农业科技和区块链在为地球的未来而战中的力量
  • 树莓派介绍
  • [神经网络]基干网络之VGG、ShuffleNet
  • Java 日期时间与正则表达式,超详细整理,适合新手入门
  • 用Netty实现物联网04:自定义通信协议
  • 「smardaten」上架钉钉应用中心!让进步再一次发生
  • 3、Maven安装
  • tkinter
  • Servlet笔记(6):HTTP状态码
  • RocketMQ 延迟队列
  • 【精准计时】北斗GPS卫星时钟同步改变精准计时年代
  • 【C#基础】C# 面向对象编程
  • 数据结构与算法入门
  • 【OpenAI】基于 Gym-CarRacing 的自动驾驶练习项目 | 路径训练功能的实现 | GYM-Box2D CarRacing
  • 亚马逊、沃尔玛测评自养号测评、退款、撸卡撸货怎么做?
  • Apollo 2.1.0最新版docker 部署多环境 与java spring boot 接入demo (附带一键部署脚本)
  • 分布式算法 - 一致性Hash算法
  • OAuth2.0入门
  • 【HTTP——了解HTTP协议及状态码】
  • 骨传导耳机靠谱吗,骨传导耳机的原理是什么
  • 对个人博客系统进行web自动化测试(包含测试代码和测试的详细过程)
  • [ 2204听力 ] 五
  • 嵌入式常问问题和知识
  • 【数据结构】空间复杂度
  • 湖南中创教育提醒校外培训留意这几点,避免维权
  • docker 配置私有/本地镜像仓库
  • 每日学术速递2.23
  • LeetCode 232. 用栈实现队列
  • AI算法创新赛-人车目标检测竞赛总结04
  • 【C语言进阶】动态内存管理详解与常见动态内存错误以及柔性数组使用与介绍