购物网站建设精英,专业仿站网站建设,宁波五金网站建设,重庆住建网官网文章目录linux 共享内存操作#xff08;shm_open#xff09;一、背景二、函数使用说明shm_openftruncate#xff08;改变文件大小#xff09;mmap共享内存三、示例代码创建内存共享文件并写入数据打开内存共享文件读数据四、问题总结shm_write.c:(.text0x18): undefined re…
文章目录linux 共享内存操作shm_open一、背景二、函数使用说明shm_openftruncate改变文件大小mmap共享内存三、示例代码创建内存共享文件并写入数据打开内存共享文件读数据四、问题总结shm_write.c:(.text0x18): 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命令可以看到。
rooti-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
rooti-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
rooti-3t537lcq:~#实际上它并不会真正的占用这块内存如果/dev/shm/下没有任何文件它占用的内存实际上就是0字节仅在使用shm_open文件时/dev/shm才会真正占用内存。
二、函数使用说明
Linux的共享内存提供了进程之间共享数据的一种方法可以避免进程之间的数据复制。Linux的共享内存API有两套即POSIX共享内存和System V共享内存。POSIX共享内存其实是基于mmap实现的。
共享内存一般基本操作流程如下
使用shm_open来新建或者打开一个共享内存如果是创建一个新的共享内存对象那么调用ftruncate设置共享内存对象的最大大小使用mmap将共享内存映射到进程的地址空间中然后操作共享内存操作完毕后使用munmap解除映射。解除映射后本进程就不能再访问共享内存但共享内存对象依然还是存在的调用close关闭shm_open返回的文件描述符。如果进程修改了共享内存那么在close之前可一调用fsync来同步。如果没有任何进程再访问共享内存对象可以调用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来删除为止。 返回值:成功返回fd0 失败返回fd0
参数说明
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 gccftruncate改变文件大小
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.hvoid *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.hchar 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执行结果
[rootdev c]# ./shm_read
ptr : 18
[rootdev c]#四、问题总结
shm_write.c:(.text0x18): undefined reference to shm_open’
问题描述 执行编译文件内容包含shm_open方法 gcc -o shm_write shm_write.c报错shm_write.c:(.text0x18): 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 timeshm_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