【APUE】进程间通信之共享存储(mmap函数)
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据: 一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间,类似虚拟内存。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
内存映射技术:
内存映射文件,是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数(CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作(直接操作文件映射到的内存)(处理存储于磁盘上的文件时,若该文件已经调入内存,则直接访问该内存,该内存是属于进程地址空间的,否则类似缺页中断,从外存中调入该文件,该文件调入到的内存地址是固定的,而处理普通文件,每次需要读写该文件时,都需要进行IO操作,调入到内存中不同地址),使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
File mapping allows the process to use both random input and output (I/O) and sequential I/O. It also allows the process to work
efficiently with a large data file, such as a database, without having to map the whole file into memory. Multiple processes can
also use memory-mapped files to share data.
有两种类型的内存映射文件:
1.共享型,在线性区页上的任何写操作都会修改磁盘上的文件;而且如果进程对共享映射中的一个页进行写,那么这种修改对于其他映射了这同一文件的所有进程来说都是可见的。所以内存映射文件也可以作为进程通信的一种方式。
2.私有型,当进程创建的映射只是为读文件,而不是写文件时才会使用这种映射。出于这种目的,私有映射的效率要比共享映射的效率更高。但是对私有映射页的任何写操作都会使内核停止映射该文件中的页。因此写操作既不会改变磁盘上的文件,对访问相同文件的其他进程也是不可见的。但是私有内存映射中的页会因为其他进程对文件的修改而更新。
采用读写函数的文件操作,至少要经过:把要处理的文件内容加载到系统内存,再从系统内存到用户指定的内存,如果你多次读写文件,就会是多次的这个 加载、复制 的操作。
而内存映射就是加载一次而已,之后就都在内存中并且可以直接使用了。
mmap()及其相关系统调用
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存(即将文件加载到内存中的某个区域)。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问(类似虚拟内存),不必再调用read(),write()等操作。
mmap()系统调用形式如下:
void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )
mmap的作用是映射文件描述符fd指定文件的 [off,off + len]区域至调用进程的[addr, addr + len]的内存区域,
返回值:若成功则返回映射区的起始地址,若出错则返回MAP_FAILED
参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的
MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的
进程间通信)。
len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
prot 参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)。
flags由以下几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必
选其一,而MAP_FIXED则不推荐使用。
offset参数一般设为0,表示从文件头开始映射。
参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函
数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。
通过共享映射的方式修改文件:
#include<stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h> #define BUF_SIZE 100 int main(int argc, char **argv)
{
int fd, nread, i;
struct stat sb;
char *mapped, buf[BUF_SIZE];
for (i = ; i < BUF_SIZE; i++) {
buf[i] = '#';
} if ((fd = open(argv[], O_RDWR)) < ) {
perror("open");
} if ((fstat(fd, &sb)) == -) {
perror("fstat");
} if ((mapped = (char *)mmap(NULL, sb.st_size, PROT_READ |PROT_WRITE, MAP_SHARED, fd, )) == (void *)-)
{
perror("mmap");
} close(fd);
printf("%s", mapped);
mapped[] = '';
if ((msync((void *)mapped, sb.st_size, MS_SYNC)) == -)
{
perror("msync");
}
if ((munmap((void *)mapped, sb.st_size)) == -)
{
perror("munmap");
}
return ;
}
参考:
http://blog.csdn.net/chdhust/article/details/8159397
http://www.cnblogs.com/Anker/archive/2013/01/16/2862800.html
【APUE】进程间通信之共享存储(mmap函数)的更多相关文章
- 共享内存:mmap函数实现
内存映射的应用: 以页面为单位,将一个普通文件映射到内存中,通常在须要对文件进行频繁读写时使用,这样用内存读写代替I/O读写,以获得较高的性能; 将特殊文件进行匿名内存映射,能够为关联进程提供共享内存 ...
- linux 进程间通信——内存共享映射mmap和munmap
IPC三种通信机制是指:信号量.共享内存.消息队列, 信号量:通过操作系统中的PV操作来实现: 共享内存:申请一块内存,进程A往共享内存中写,其他的进程就可以通过读出共享内存中的内容来获取进程A所 ...
- UNIX环境高级编程——存储映射I/O(mmap函数)
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共 ...
- 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap
IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...
- 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等
一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...
- 共享内存简介和mmap 函数
一.共享内存简介 共享内存区是最快的IPC形式,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据. 即每个进程地址空间都有一个共享存储器的映射区,当这块区 ...
- Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)
有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...
- linux进程间通信之共享内存篇
本文是对http://www.cnblogs.com/andtt/articles/2136279.html中共享内存(上)的进一步阐释说说明 1 共享内存的实现原理 共享内存是linux进程间通讯的 ...
- Linux环境进程间通信(五): 共享内存(下)
linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...
随机推荐
- typescript知识教程
https://ts.xcatliu.com/basics/type-of-function.html
- Java中wait()方法为什么要放在同步块中?(lost wake-up 问题)
问题起源 事情得从一个多线程编程里面臭名昭著的问题"Lost wake-up problem"说起. 这个问题并不是说只在Java语言中会出现,而是会在所有的多线程环境下出现. 假 ...
- MyBatis基本运行环境
MyBatis基本运行环境 1. 创建项目 2.拷贝jar加入到项目中build path jar包 3.创建数据库的表及数据添加 USE [mybatis] CREATE TABLE [dbo].[ ...
- Perl中 qw 是 “quoted Word” 或是 “quoted by whitespace”的简写
Perl中 qw 是 “quoted Word” 或是 “quoted by whitespace”的简写 eg: @strict_pragma = qw ( a b c);
- Navicat 模型生成表
打开模型 -> 左上角文件 -> 导出SQL 打开sql文件,将sql在数据库执行,注意主键递增.日期类型 根据当前时间戳更新是否需要(默认选中的)等等
- 文件默认权限umask掩码
umask命令 作用:用于显示.设置文件的缺省权限 格式:umask [-S] -S表示以rwx形式显示新建文件缺省权限 系统的默认掩码是0022 文件创建时的默认权限 = 0666 - umas ...
- 枚举为何不能设置成public?
听到测试与开发争论,为何枚举不能用public,用public怎么了?对于这个我也不知道到底能不能用,于是就去查了查资料. 解答: 枚举被设计成是单例模式,即枚举类型会由JVM在加载的时候,实例化枚举 ...
- mysql EXPLAIN Join Types 手册解释 及数据实操
第一部分:名称解释 文档地址 https://dev.mysql.com/doc/refman/5.7/en/explain-output.html EXPLAIN Join Types: The ...
- python 模块学习(二)
一.日志模块(logging ) 日志是一种追踪软件运行时所发生事件的方法 1.简单的日志编写(文件输出) import logging # 日志模块 # 日志配置,把日志内容存到文件中 loggin ...
- [NOI2001] 炮兵阵地 (状压Dp经典例题)
如果您的电脑比较优秀能在 1sec 内跑过 2^1000 的时间复杂度,不妨你可以尝试一下,其实实际时间复杂度远远少于 2^1000,作为骗分不错的选择QAQ,然后我们来分析一下正解: 很显然此题是一 ...