前言

最近在学习GNU/Linux内核,看到mmap的时候书上说:

mmap/munmap接口函数是用户最常用的两个系统调用接口,无论是在用户程序中分配内存、读写大文件、链接动态库文件,还是多进程间共享内存,都可以看到mmap/munmap的身影。

这句话说的很正确,虽然我们日常没有直接使用mmap,但是其实我们都间接地使用了mmap/mumap函数。

举个例子,我们使用动态链接库的时候,我们都知道,动态链接不会把动态库中的代码整合到目标文件中,相反,动态库跟目标文件独立。

那为什么运行时,程序能够获得指定的符号链接?这正是mmap的力量,程序运行时,他将保存在物理内存的动态库的内容(如果物理内存中没有,则先加载如内存)映射到自身的进程地址空间,这样符号所对应的指令数据便存在了。

(通过ldd可获取所依赖的动态库,Linux怎么获取到的,我怀疑跟ELF文件格式有关,待解答)

mmap

mmap是内存映射文件的方法

mmap将一个文件或者其它对象映射进内存。mmap在用户空间映射调用系统中作用很大。

mmap()必须以PAGE_SIZE为单位进行映射,而内存也只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行内存对齐,强行以PAGE_SIZE的倍数大小进行映射。

头文件

函数原型

void* mmap(void* addr, size_t length,int prot,int flags,int fd,off_t offset); int munmap(void* start,size_t length);

  • addr: 用于指定映射到进程地址的起始地址,为了应用程序的可移植性,一般设为nullptr;
  • length: 表示映射到进程地址空间的大小;
  • prot: 表示设置内存映射区域的读写属性等;
  • flags: 用于设置内存映射的属性,例如共享映射、私有映射、匿名映射等;
  • fd: 文件句柄,如果不是文件映射,则置为0;
  • offset: 文件映射时的文件偏移量。

重复一遍:由于GNU/Linux中,内存分配是以页为单位的,所以length长度不足1页(默认4KB),则按1页来处理。

prot参数detail:

flags参数detail:

共享内存

共享内存Shared Memory,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。

具体来说,共享内存就是一段真实存在的物理内存,不同进程通过访问和修改该段物理内存,最终达到共享内存的目的。

PS: 共享内存不提供数据同步机制,如一个进程在写过程中,另一个进程可以进行读操作和写操作,所以需要通过信号量来解决同步问题。

创建共享内存

函数介绍

函数原型如下:

#include #include         /* For mode constants */#include            /* For O_* constants */int shm_open(const char *name, int oflag, mode_t mode);int shm_unlink(const char *name);Link with -lrt.

shm_open()创建并打开一个新的或现有的POSIX共享内存对象。POSIX共享内存对象实际上是一个句柄,它可以被与mmap共享内存相同区域的无关进程使用。

shm_unlink()函数的作用是:删除先前由shm_open()创建的对象。

函数用法

int fd = shm_open("/shm01", O_CREAT | O_RDWR, 0777);

当oflag使用O_CREAT时,mode表示创建文件时的权限,权限写法跟命令chmod一样(https://www.runoob.com/linux/linux-comm-chmod.html)。

open与shm_open区别

或许你会问:如果是创建一个文件何必使用shm_open呢?为什么不使用open?

理论上来说两个方法可以相互替换。

但是,很重要的一点是:shm_open会将文件创建在/dev/shm目录下,该目录下挂载的文件系统格式是tmpfs,该目录下的文件也只存储在内存(主存)中。如果你使用open方法在该目录下创建和打开文件其实两者就没有本质区别了。

如图所示,/dev/shm是tmpfs文件系统

进程间通讯实例

本测试用例需要依赖googletest测试框架,当然读者可以通过分别建立两个项目来实现下述实例;

实例原理

如图所示,共享内存创建后保存在真实的物理内存中,通过mmap函数我们将该物理内存地址映射到进程地址空间中,最终实现操作共享内存的功能。

实例功能

服务端:创建共享内存,并将内存映射到进程地址空间中,然后进行定时修改内存内容。

客户端:映射共享内存到进程地址空间中,定时获取内存内容。

实例代码

服务端代码

#include #include #include #include TEST(shm_test, server) {    int fd = shm_open("/shm01", O_CREAT | O_RDWR, 0777);    // int fd = open("/dev/shm/shm01", O_CREAT | O_RDWR);    if (fd < 0) {        std::cout << "error to create or open" << std::endl;        return;    }    std::cout << "create or open ok" << std::endl;    ftruncate(fd, 4096);// 分配4KB内存    char *ptr = (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    close(fd);    char a[] = "00";    for (char k = 0; k < 26; ++k) {        memset(a, 'a' + k, 1 *sizeof(char));        strcpy(ptr, a);        sleep(1);    }    strcpy(ptr, a);    mumap((void *)ptr, 4096); // 关闭映射    exit(0);}

客户端代码

#include #include #include #include TEST(test, client) {    int fd = shm_open("/shm01", O_RDWR, 0777);    // int fd = open("/dev/shm/shm01", O_CREAT | O_RDWR);    if (fd < 0) {        std::cout << "error to open" << std::endl;        return;    }    char *ptr = (char *)mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    close(fd);    while(true) {        std::cout << ptr << std::endl;        sleep(1);    }    exit(0);}

执行结果

开头的z是之前保存在共享内存中的数据

可以看到客户端输出了英语字母。

遇到的问题

  1. 找不到shm_open的符号链接

答:在编译时链接rt库

  1. 使用googletest时,缺失pthread

答:链接pthread库

总结

本篇文章,我们知道了共享内存,通过共享内存和mmap我们能很轻易地完成进程间通讯(IPC Inter-Process Communication),进程间的semaphore(信号量)实现方式也是通过mmap和共享变量实现的。

文章出处:https://my.oschina.net/StupidZhe/blog/4647178

linux open 头文件_linux下通过共享内存和mmap实现进程间通讯相关推荐

  1. linux mmap实例_Linux下通过共享内存和mmap实现进程间通讯(含实例)

    前言 最近在学习GNU/Linux内核,看到mmap的时候书上说: mmap/munmap接口函数是用户最常用的两个系统调用接口,无论是在用户程序中分配内存.读写大文件.链接动态库文件,还是多进程间共 ...

  2. linux major头文件_Linux的字符设备

    Linux中很多设备都是字符设备,使用ls -l查看/dev下的设备,前面带c的都是字符设备. 字符设备的创建比较容易,而且有一套固定的模式,掌握了模式完全可以"套模板".更多的精 ...

  3. java thread 头文件_Linux 下 C++ 的多线程基类 - Thread

    在原来的基础上,进行了加强,使之进一步接近 Java 中 Thread 和 Runnable 的用法. 下面是我写的基类,把代码保存在名为 Thread.h 的头文件中. ============== ...

  4. Linux应用开发5 信号(软中断,处理异步请求,进程间通讯)

            信号是事件发生时对进程的通知机制,也可以把它称为软件中断.信号与硬件中断的相似之处在于能够 打断程序当前执行的正常流程,其实是在软件层次上对中断机制的一种模拟.大多数情况下,是无法预测 ...

  5. ftp linux 推送文件_Linux下SSH用FTP命令上传文件至另一个FTP空间

    如果没有ftp 提示: -bash: ftp: command not found 请先安装ftp应用程序: yum install ftp #ftp 127.0.0.1 21 输入远程空间的FTP ...

  6. 【Linux】-- 进程间通讯

    目录 进程间通讯概念的引入 意义(手段) 思维构建 进程间通信方式 管道 站在用户角度-浅度理解管道 匿名管道 pipe函数 站在文件描述符角度-深度理解管道 管道的特点总结 管道的拓展 单机版的负载 ...

  7. java 内存映射文件进程间通讯_[转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile...

    进程间的通信方式有很多种, 上次我们说了最傻瓜的"共享外存/文件"的方法. 那么, 在本文中, 我们即将学习"共享内存"的方式实现进程间的通信, 这是IPC最快 ...

  8. Linux下进程间通信--共享内存:最快的进程间通信方式

    内存共享最新整理: Linux下进程间通信-共享内存 - 码到城攻共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式https://www.codecomeon.com/posts/109/ ...

  9. Linux C try 头文件,linux c 头文件

    //1.Linux中一些头文件的作用: #include //ANSI C.提供断言,assert(表达式) #include //GCC.GTK,GNOME的基础库,提供很多有用的函数,如有数据结构 ...

最新文章

  1. anaconda3配置环境变量_Python:Anaconda安装及LabelMe配置(1)
  2. python selenium --处理下拉框
  3. 对于多个 BAPI一起commit!
  4. 科大星云诗社动态20210516
  5. 2019/01/29-Linux常用指令
  6. Android 自定义 ListView 显示网络上 JSON 格式歌曲列表
  7. 数据结构之树的存储结构
  8. python控制鼠标_如何使用Python在Mac中控制鼠标?
  9. 哈希表(散列表)冲突解决方法
  10. luogu_4551【题解】最长异或路径 trie树
  11. CSDN 博客前200名
  12. arduino中利用LiquidCrystal内置的scrool函数实现屏幕文字滚动播放
  13. 华硕笔记本bios设置u盘启动
  14. 子目录和子域名哪个好?子目录和子域名如何利用seo优化?
  15. 商城项目商品列表页的渲染实现(含动图)
  16. FinalShell连接不上LinuxCentOS-7的解决方案
  17. Python进行网页自动打卡系统
  18. 计算机应用中英文缩写ai表示,2012浙江省全国计算机等级考试二级VB笔试试卷及参考答案考资料...
  19. 【Python 18】BMR计算器2.0(数值类型转换与while循环)
  20. HTML-腾讯软件中心

热门文章

  1. sql随机抽取数据50条_MySQL中随机抽样
  2. pytorch argmax_轻松学Pytorch使用ResNet50实现图像分类
  3. PHP ajax 传递中文乱码,ajax+php传递中文乱码解决办法
  4. 微信小程序的不同函数调用的几种方法
  5. php传递字符串给python,用PHP和Python生成短链接服务的字符串ID
  6. 召回粗排精排-级联漏斗(下)
  7. NLP Subword三大算法原理:BPE、WordPiece、ULM
  8. CUDA层硬件debug之路
  9. 我对DevOps的理解
  10. 论文浅尝 - TACL2020 | TYDI QA:Google 发表一个多语言的问答语料库