共享内存简介和mmap 函数
一、共享内存简介
共享内存区是最快的IPC形式,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
即每个进程地址空间都有一个共享存储器的映射区,当这块区域都映射到相同的真正的物理地址空间时,可以通过这块区域进行数据交换,例如共享库就是这么实现的,很多进程都会使用同一个函数如printf,也许在真正的物理地址空间中只存在一份printf.o
,然后所有进程都映射到这一份printf.o 就实现了共享。
用管道或者消息队列传递数据:
用共享内存传递数据:
即使用共享内存传递数据比用消息队列和管道来说,减少了进入内核的次数,提高了效率。
二、mmap 函数
#include <sys/mman.h>
功能:将文件或者设备空间映射到共享内存区。
原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
参数
addr: 要映射的起始地址,通常指定为NULL,让内核自动选择
len:映射到进程地址空间的字节数
prot:映射区保护方式
flags:标志
fd:文件描述符
offset:从文件头开始的偏移量,必须是页大小的整数倍(在32位体系统结构上通常是4K)
返回值:成功返回映射到的内存区的起始地址;失败返回-1
prot 参数取值:
PROT_EXEC 表示映射的这一段可执行,例如映射共享库
PROT_READ 表示映射的这一段可读
PROT_WRITE 表示映射的这一段可写
PROT_NONE 表示映射的这一段不可访问
flag参数有很多种取值,这里只讲两种,其它取值可查看mmap(2)
MAP_SHARED 多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。
MAP_PRIVATE 多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
内存映射文件示意图:
如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射:
功能:取消mmap函数建立的映射
原型 int munmap(void *addr, size_t len);
参数
addr: 映射的内存起始地址
len:映射到进程地址空间的字节数
返回值:成功返回0;失败返回-1
下面写两个程序测试一下:
mmap_write.c
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#include<string.h>
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #define ERR_EXIT(m) \ typedef struct stu int main(int argc, char *argv[]) int fd; lseek(fd, sizeof(STU) * 5 - 1, SEEK_SET); STU *p; if (p == -1) char ch = 'a'; printf("initialize over\n"); munmap(p, sizeof(STU) * 5); |
mmap_read.c
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#include<string.h>
#include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> #include<fcntl.h> #include<sys/stat.h> #include<sys/mman.h> #define ERR_EXIT(m) \ typedef struct stu int main(int argc, char *argv[]) int fd; STU *p; if (p == -1) int i; |
先运行mmap_write ,然后用od -c 查看文件内容:
initialize over
exit...
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ od -c test
0000000 a \0 \0 \0 024 \0 \0 \0 b \0 \0 \0 025 \0 \0 \0
0000020 c \0 \0 \0 026 \0 \0 \0 d \0 \0 \0 027 \0 \0 \0
0000040 e \0 \0 \0 030 \0 \0 \0
0000050
name = a age = 20
name = b age = 21
name = c age = 22
name = d age = 23
name = e age = 24
exit...
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$
再次将文件test 映射到内存,然后从内存读取到了文件的内容。
mmap 编程注意点:
1、映射不能改变文件的大小;
2、可用于进程间通信的有效地址空间不完全受限于被映射文件的大小;
3、文件一旦被映射后,所有对映射区域的访问实际上是对内存区域的访问。映射区域内容写回文件时,所写内容不能超过文件的大小;
对于1,3点,将mmap_write.c 中40行以后的代码中的5改成10,即映射的内存大于文件的大小,这样写入是不会出错的,因为是向内存写入,但用od 查看时发现文件还是40 个字节,即只有前5个STU才被真正写入到了文件。
对于第2点,将mmap_write.c 和 mmap_read.c 都按上面说的更改成10,然后在mmap_write.c 中munmap 函数之前sleep(10); 先运行mmap_write,再在另一终端运行mmap_read,观察结果:
simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./mmap_read test
name = a age = 20
name = b age = 21
name = c age = 22
name = d age = 23
name = e age = 24
name = f age = 25
name = g age = 26
name = h age = 27
name = i age = 28
name = j age = 29
exit...
即在mmap_write
对映射内存区域写入之后尚未取消映射时,mmap_read 也映射了test
文件,两个虚拟进程地址空间的映射区域都指向了同一块物理内存,所以也能读到write 进程对内存的修改,但进程结束后查看test
文件,还是40个字节而已。内存的映射是以页面为单位的,一般为4k,所以才有第2条的说法,其实这才是真正体现共享内存可以进程间通信的所在。
最后一点,与write 类似,将文件映射到内存后对内存进行写入,不一定会马上写回文件,有可能内核也会产生一个缓冲区,找个适当的时间内核再写回设备文件,write 之后可以调用fsync 进行同步,同样地,mmap 可以调用msync 进行同步。
参考:
《linux c 编程一站式学习》
《UNP》
共享内存简介和mmap 函数的更多相关文章
- Linux环境编程之共享内存区(一):共享内存区简单介绍
共享内存区是可用IPC形式中最快的.一旦内存区映射到共享它的进程的地址空间,进程间数据的传递就不再涉及内核.然而往该共享内存区存放信息或从中取走信息的进程间通常须要某种形式的同步.不再涉及内核是指:进 ...
- Linux下多任务间通信和同步-mmap共享内存
Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...
- mmap和shm共享内存的区别和联系
共享内存的创建 根据理论: 1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿 ...
- linux下共享内存mmap和DMA(直接访问内存)的使用 【转】
转自:http://blog.chinaunix.net/uid-7374279-id-4413316.html 介绍Linux内存管理和内存映射的奥秘.同时讲述设备驱动程序是如何使用“直接内存访问” ...
- mmap映射区和shm共享内存的区别总结
[转载]原文链接:https://blog.csdn.net/hj605635529/article/details/73163513 linux中的两种共享内存.一种是我们的IPC通信System ...
- mmap映射文件至内存( 实现 共享内存 与 文件的另类访问 )
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明: 头文件: < ...
- (转)mmap和shm共享内存的区别和联系
共享内存的创建 根据理论: 1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用 ...
- 共享内存之——mmap内存映射
共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制.共享内存可以通过mmap()映射普通文件 (特殊情况下还可以采用匿名映射)机制实现,也可以通过sy ...
- 细说linux IPC(三):mmap系统调用共享内存
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 前面讲到socket的进程间通 ...
随机推荐
- 【ES】elasticsearch学习笔记
ES学习 1 优势 1.1 简单 1.1.1 相比Solor配置部署等非常简单 1.2 高效 1.2.1 ES使用Netty作为内部RPC框架,Solor使用Jetty 1.3 插件化 1.3.1 E ...
- Java--解压缩zip包
Test.java import java.io.IOException; public class Test { public static void main(String[] args) thr ...
- MATLAB数据处理快速学习教程
转自:http://blog.csdn.net/abcjennifer/article/details/7706581 本篇内容集合了MATLAB中的基本操作.数据存储与计算.数据的直线与曲线拟合与画 ...
- @QueryParam和@PathParam使用方法比较
1 先来看@queryparam Path("/users") public class UserService { @GET @Path("/query") ...
- ZH奶酪:在博客中添加Latex公式
1. 点击编辑器中的插入图片: 2.在URL输入下边的地址: http://latex.codecogs.com/gif.latex?你的latex代码 就可以了-
- 与AQS有关的并发类
ReetrantLock与Condition: 參考 在java.util.concurrent包中.有两个非常特殊的工具类.Condition和ReentrantLock,使用过的人都知道,Reen ...
- WQL语言简介和WQL测试工具wbemtest.exe使用方法详细介绍
这篇文章主要介绍了WQL语言简介和WQL测试工具wbemtest.exe使用方法详细介绍,WQL是指Windows管理规范查询语言,需要的朋友可以参考下 WQL就是WMI中的查询语言,WQL的全称是W ...
- java面试第七天
反射: 反射:在运行时动态分析或使用一个类进行工作. java.lang.Class类:描述类信息的类. 类对象:描述一个类信息的对象,当虚拟机加载类的时候,就会创建这个类的类对象并加载该对象,Cla ...
- MySQL查看表结构三种方法
1:desc T1 2:EXPLAIN T1 3:SHOW COLUMNS FROM T1
- KnockoutJS + My97DatePicker
如何将Knockoutjs和其他脚本库结合使用?这里给出一个Knockoutjs与my97datepicker配合使用的例子,例子中使用了ko的自定义绑定功能: ko.bindingHandlers. ...